void Project::readPlatformSettings( const QString &contents, const QString &setting, QMap<QString, QString> &res ) { const QString platforms[] = { "", "win32", "unix", "mac", "os2", QString::null }; for ( int i = 0; platforms[ i ] != QString::null; ++i ) { QString p = platforms[ i ]; if ( !p.isEmpty() ) p += ":"; QStringList lst = parse_multiline_part( contents, p + setting ); QString s = lst.join( " " ); QString key = platforms[ i ]; if ( key.isEmpty() ) key = "(all)"; res.replace( key, s ); } }
void Project::save( bool onlyProjectFile ) { bool anythingModified = FALSE; // save sources and forms if ( !onlyProjectFile ) { saveConnections(); for ( SourceFile *sf = sourcefiles.first(); sf; sf = sourcefiles.next() ) { anythingModified = anythingModified || sf->isModified(); if ( !sf->save() ) return; } for ( FormFile *ff = formfiles.first(); ff; ff = formfiles.next() ) { anythingModified = anythingModified || ff->isModified(); if ( !ff->save() ) return; } } if ( isDummy() || filename.isEmpty() ) return; if ( !modified ) { if ( singleProjectMode() ) { LanguageInterface *iface = MetaDataBase::languageInterface( language() ); if ( iface && iface->supports( LanguageInterface::CompressProject ) ) iface->compressProject( makeAbsolute( filename ), singleProFileName, anythingModified ); } return; } QFile f( filename ); QString original = ""; // read the existing file bool hasPreviousContents = FALSE; if ( f.open( IO_ReadOnly ) ) { QTextStream ts( &f ); original = ts.read(); f.close(); hasPreviousContents = TRUE; remove_contents( original, "{SOURCES+=" ); // ### compatibility with early 3.0 betas remove_contents( original, "DBFILE" ); remove_contents( original, "LANGUAGE" ); remove_contents( original, "TEMPLATE" ); removePlatformSettings( original, "CONFIG" ); removePlatformSettings( original, "DEFINES" ); removePlatformSettings( original, "LIBS" ); removePlatformSettings( original, "INCLUDEPATH" ); removePlatformSettings( original, "SOURCES" ); removePlatformSettings( original, "HEADERS" ); remove_multiline_contents( original, "FORMS" ); remove_multiline_contents( original, "INTERFACES" ); // compatibility remove_multiline_contents( original, "IMAGES" ); for ( QStringList::Iterator it = csList.begin(); it != csList.end(); ++it ) remove_contents( original, *it ); } if (!original.isEmpty()) { // Removes any new lines at the beginning of the file while (original.startsWith("\n")) original.remove(0, 1); } // the contents of the saved file QString contents; // template contents += "TEMPLATE\t= " + templ + "\n"; // language contents += "LANGUAGE\t= " + lang + "\n"; contents += "\n"; // config writePlatformSettings( contents, "CONFIG", cfg ); LanguageInterface *iface = MetaDataBase::languageInterface( lang ); if ( iface ) { QStringList sourceKeys; iface->sourceProjectKeys( sourceKeys ); for ( QStringList::Iterator spit = sourceKeys.begin(); spit != sourceKeys.end(); ++spit ) remove_multiline_contents( contents, *spit ); } // libs, defines, includes writePlatformSettings( contents, "LIBS", lbs ); writePlatformSettings( contents, "DEFINES", defs ); writePlatformSettings( contents, "INCLUDEPATH", inclPath ); writePlatformSettings( contents, "SOURCES", sources ); writePlatformSettings( contents, "HEADERS", headers ); // unix if ( !hasPreviousContents ) { contents += "unix|os2 {\n" " UI_DIR = .ui\n" " MOC_DIR = .moc\n" " OBJECTS_DIR = .obj\n" "}\n\n"; } // sources if ( !sourcefiles.isEmpty() && iface ) { QMap<QString, QStringList> sourceToKey; for ( SourceFile *f = sourcefiles.first(); f; f = sourcefiles.next() ) { QString key = iface->projectKeyForExtension( QFileInfo( f->fileName() ).extension() ); QStringList lst = sourceToKey[ key ]; lst << makeRelative( f->fileName() ); sourceToKey.replace( key, lst ); } for ( QMap<QString, QStringList>::Iterator skit = sourceToKey.begin(); skit != sourceToKey.end(); ++skit ) { QString part = skit.key() + "\t+= "; QStringList lst = *skit; for ( QStringList::Iterator sit = lst.begin(); sit != lst.end(); ++sit ) { part += *sit; part += ++sit != lst.end() ? " \\\n\t" : ""; --sit; } part += "\n\n"; contents += part; } } // forms and interfaces if ( !formfiles.isEmpty() ) { contents += "FORMS\t= "; for ( QPtrListIterator<FormFile> fit = formfiles; fit.current(); ++fit ) { contents += fit.current()->fileName() + (fit != formfiles.last() ? " \\\n\t" : ""); } contents += "\n\n"; } // images if ( !pixCollection->isEmpty() ) { contents += "IMAGES\t= "; QValueList<PixmapCollection::Pixmap> pixmaps = pixCollection->pixmaps(); for ( QValueList<PixmapCollection::Pixmap>::Iterator it = pixmaps.begin(); it != pixmaps.end(); ++it ) { contents += makeRelative( (*it).absname ); contents += ++it != pixmaps.end() ? " \\\n\t" : ""; --it; } contents += "\n\n"; } // database if ( !dbFile.isEmpty() ) contents += "DBFILE\t= " + dbFile + "\n"; // custom settings for ( QStringList::Iterator it = csList.begin(); it != csList.end(); ++it ) { QString val = *customSettings.find( *it ); if ( !val.isEmpty() ) contents += *it + "\t= " + val + "\n"; } if ( !f.open( IO_WriteOnly | IO_Translate ) ) { QMessageBox::warning( messageBoxParent(), "Save Project Failed", "Couldn't write project file " + filename ); return; } QTextStream os( &f ); os << contents; if (hasPreviousContents) os << original; f.close(); setModified( FALSE ); if ( singleProjectMode() ) { LanguageInterface *iface = MetaDataBase::languageInterface( language() ); if ( iface && iface->supports( LanguageInterface::CompressProject ) ) iface->compressProject( makeAbsolute( filename ), singleProFileName, TRUE ); } }
QMap<QString, QString> proFileTagMap( const QString& text ) { QString t = text; QMap<QString, QString> tagMap; bool stillProcess = true; // If include() has a $$tag then we need to reprocess while(stillProcess) { /* Strip any commments before we try to include. We still need to do it after we include to make sure the included file does not have comments */ t.replace( QRegExp(QString("#[^\n]*\n")), QString(" ") ); /* Process include() commands. $$PWD is a special case so we have to change it while we know where the included file is. */ QRegExp callToInclude("include\\s*\\(\\s*([^()\\s]+)\\s*\\)"); int i = 0; while ( (i = callToInclude.search(t, i)) != -1 ) { bool doneWithVar = false; QString fileName = callToInclude.cap(1); QString after = fileName.replace("$$PWD", QDir::currentDirPath()); if (!tagMap.isEmpty() && after.contains("$$")) { QRegExp var( "\\$\\$[({]?([a-zA-Z0-9_]+)[)}]?" ); int ii = 0; while ((ii = after.find(var, ii)) != -1) { if (tagMap.contains(var.cap(1))) { after.replace(ii, var.cap(0).length(), tagMap[var.cap(1)]); } else { // Couldn't find it doneWithVar = true; break; } } } if (doneWithVar || !after.contains("$$")) { after = loadFile(after); QFileInfo fi(callToInclude.cap(1)); after.replace("$$PWD", fi.dirPath()); t.replace( i, callToInclude.matchedLength(), after ); } i += after.length(); } /* Strip comments, merge lines ending with backslash, add spaces around '=' and '+=', replace '\n' with ';', and simplify white spaces. */ t.replace( QRegExp(QString("#[^\n]*\n")), QString(" ") ); t.replace( QRegExp(QString("\\\\[^\n\\S]*\n")), QString(" ") ); t.replace( "=", QString(" = ") ); t.replace( "+ =", QString(" += ") ); t.replace( "\n", QString(";") ); t = t.simplifyWhiteSpace(); /* Populate tagMap with 'key = value' entries. */ QStringList lines = QStringList::split( QChar(';'), t ); QStringList::Iterator line; for ( line = lines.begin(); line != lines.end(); ++line ) { QStringList toks = QStringList::split( QChar(' '), *line ); if ( toks.count() >= 3 && (toks[1] == QString("=") || toks[1] == QString("+=")) ) { QString tag = toks.first(); int k = tag.findRev( QChar(':') ); // as in 'unix:' if ( k != -1 ) tag = tag.mid( k + 1 ); toks.remove( toks.begin() ); QString action = toks.first(); toks.remove( toks.begin() ); if ( tagMap.contains(tag) ) { if ( action == QString("=") ) tagMap.replace( tag, toks.join(QChar(' ')) ); else tagMap[tag] += QChar( ' ' ) + toks.join( QChar(' ') ); } else { tagMap[tag] = toks.join( QChar(' ') ); } } } /* Expand $$variables within the 'value' part of a 'key = value' pair. */ QRegExp var( "\\$\\$[({]?([a-zA-Z0-9_]+)[)}]?" ); QMap<QString, QString>::Iterator it; for ( it = tagMap.begin(); it != tagMap.end(); ++it ) { int i = 0; while ( (i = var.search((*it), i)) != -1 ) { int len = var.matchedLength(); QString invocation = var.cap(1); QString after; if ( invocation == "system" ) { // skip system(); it will be handled in the next pass ++i; } else { if ( tagMap.contains(invocation) ) after = tagMap[invocation]; else if (invocation.lower() == "pwd") after = QDir::currentDirPath(); (*it).replace( i, len, after ); i += after.length(); } } } /* Execute system() calls. */ QRegExp callToSystem( "\\$\\$system\\s*\\(([^()]*)\\)" ); for ( it = tagMap.begin(); it != tagMap.end(); ++it ) { int i = 0; while ( (i = callToSystem.search((*it), i)) != -1 ) { /* This code is stolen from qmake's project.cpp file. Ideally we would use the same parser, so we wouldn't have this code duplication. */ QString after; char buff[256]; FILE *proc = QT_POPEN( callToSystem.cap(1).latin1(), "r" ); while ( proc && !feof(proc) ) { int read_in = (int)fread( buff, 1, 255, proc ); if ( !read_in ) break; for ( int i = 0; i < read_in; i++ ) { if ( buff[i] == '\n' || buff[i] == '\t' ) buff[i] = ' '; } buff[read_in] = '\0'; after += buff; } (*it).replace( i, callToSystem.matchedLength(), after ); i += after.length(); } } stillProcess = callToInclude.search(t) != -1; } return tagMap; }