src/hbtools/hbbincssmaker/main.cpp
changeset 5 627c4a0fd0e7
parent 2 06ff229162e9
child 7 923ff622b8b9
equal deleted inserted replaced
3:11d3954df52a 5:627c4a0fd0e7
    30 #include <hbmemoryutils_p.h>
    30 #include <hbmemoryutils_p.h>
    31 #include <hbcssparser_p.h>
    31 #include <hbcssparser_p.h>
    32 #include <hbsharedmemorymanager_p.h>
    32 #include <hbsharedmemorymanager_p.h>
    33 #include <hbsharedcache_p.h>
    33 #include <hbsharedcache_p.h>
    34 #include <hbcssconverterutils_p.h>
    34 #include <hbcssconverterutils_p.h>
       
    35 #include <hboffsetmapbuilder_p.h>
       
    36 #include <hbwidgetloader_p.h>
    35 
    37 
    36 // Global variables
    38 // Global variables
    37 QString AppName("hbbincssmaker");
    39 static const QString CSSFileExtension = ".css";
       
    40 static const QString WMLFileExtension = ".widgetml";
       
    41 static const QString ColorCSSEnding = "_color.css";
       
    42 
       
    43 static const QString AppName = "hbbincssmaker";
    38 static bool verboseOn = false;
    44 static bool verboseOn = false;
       
    45 
    39 QTextStream out(stdout);
    46 QTextStream out(stdout);
    40 QTextStream verboseOut(stderr);
    47 QTextStream verboseOut(stderr);
    41 QTextStream err(stderr);
    48 QTextStream err(stderr);
    42 
    49 
    43 #define VERBOSE(statement) if(verboseOn) { verboseOut << statement; }
    50 #define VERBOSE(statement) if(verboseOn) { verboseOut << statement; }
    44 #define VERBOSEIF(test, statement) if(verboseOn && test) { verboseOut << statement; }
    51 #define VERBOSEIF(test, statement) if(verboseOn && test) { verboseOut << statement; }
    45 #define VERBOSELN(statement) if(verboseOn) { verboseOut << statement << endl; }
    52 #define VERBOSELN(statement) if(verboseOn) { verboseOut << statement << endl; }
    46 
    53 
       
    54 struct WidgetMLParseInput
       
    55 {
       
    56     QString filename;
       
    57     QList<CSSLayoutInfo> layouts;
       
    58 
       
    59     void clear()
       
    60     {
       
    61         layouts.clear();
       
    62         filename.clear();
       
    63     }
       
    64 };
    47 
    65 
    48 void testDeclarations(const HbVector<HbCss::Declaration> &decls)
    66 void testDeclarations(const HbVector<HbCss::Declaration> &decls)
    49 {
    67 {
    50     VERBOSE("declarations count: ");
    68     VERBOSE("declarations count: ");
    51     VERBOSELN(decls.count());
    69     VERBOSELN(decls.count());
   113         testStyleRules(rule.portraitRules);
   131         testStyleRules(rule.portraitRules);
   114         testStyleRules(rule.landscapeRules);
   132         testStyleRules(rule.landscapeRules);
   115     }
   133     }
   116 }
   134 }
   117 
   135 
   118 class CssMap
   136 void testLayoutDef(const HbWidgetLoader::LayoutDefinition *layoutDef)
   119 {
   137 {
   120 public:
   138     VERBOSELN("mesh items count: " << layoutDef->meshItems.count());
   121     CssMap() {}
   139     for (int i = 0; i < layoutDef->meshItems.count(); ++i) {
   122     void add(const QString &cssName, unsigned int offset)
   140         const HbWidgetLoader::MeshItem &meshItem = layoutDef->meshItems.at(i);
   123     {
   141         VERBOSELN("src: " << meshItem.src);
   124         HbOffsetItem mapItem = _mapItems.value(cssName, HbOffsetItem());
   142         VERBOSELN("dst: " << meshItem.dst);
   125         if (mapItem.nameOffset < 0) {
   143         VERBOSELN("spacing text: " << meshItem.spacingText);
   126             mapItem.nameOffset = _cssNameBuffer.size();
   144         VERBOSELN("spacer: " << meshItem.spacer);
   127             mapItem.offset = offset;
   145     }
   128             _cssNameBuffer.append(cssName.toLatin1()).append('\0');
   146 }
   129             _mapItems.insert(cssName, mapItem);
   147 
   130         } else {
   148 bool testCss()
   131             err << "warning: duplicate cache key for " << cssName << endl;
   149 {
   132         }
   150     GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory);
   133     }
   151     HbSharedMemoryManager *shared = static_cast<HbSharedMemoryManager*>(manager);
   134 
   152     HbSharedCache *cache = shared->cache();
   135     void registerOffsetHolders() {
   153 
   136         foreach(const HbOffsetItem &mapItem, _mapItems) {
   154     for (int k = 0; k < cache->mOffsetItemCount; ++k) {
   137             HbCssConverterUtils::registerOffsetHolder(const_cast<int *>(&mapItem.offset));
   155         if (cache->mOffsetItems[k].offsetCSS >= 0) {
   138         }
   156             HbCss::StyleSheet *sheet = HbMemoryUtils::getAddress<HbCss::StyleSheet>(
   139     }
   157                 HbMemoryManager::SharedMemory, cache->mOffsetItems[k].offsetCSS);
   140 
   158             VERBOSELN("Cssmap item " << k
   141     QByteArray data() const {
   159                     << "- hash value: \"" << cache->mOffsetItems[k].offsetCSS << "\"");
   142         QByteArray dataArray;
   160             // Tests the stylesheet offsets and prints info to verbose out
   143         int count = _mapItems.size();
   161             testStyleSheet(sheet);
   144         int adjustment = count * sizeof(HbOffsetItem);
   162 
   145         foreach(const HbOffsetItem &mapItem, _mapItems) {
   163             //test layout definition.
   146             HbOffsetItem tmp(mapItem);
   164             int tableSize = 0;
   147             // Fix offsets in the items to be based on the beginning of the css map instead of
   165             const HbLayoutIndexItem *ptr = cache->layoutIndexItemBegin(
   148             // the beginning of the css name buffer.
   166                     cache->mOffsetItems[k].offsetLayoutIndexTable, &tableSize);
   149             tmp.nameOffset += adjustment;
   167             for (; tableSize > 0; --tableSize, ++ptr) {
   150             dataArray.append(reinterpret_cast<const char*>(&tmp), sizeof(HbOffsetItem));
   168                 HbWidgetLoader::LayoutDefinition *layoutDef =
   151         }
   169                     HbMemoryUtils::getAddress<HbWidgetLoader::LayoutDefinition>(
   152         dataArray.append(_cssNameBuffer);
   170                             HbMemoryManager::SharedMemory, ptr->offset);
   153         return dataArray;
   171                 testLayoutDef(layoutDef);
   154     }
   172             }
   155     int size() const { return _mapItems.count(); }
   173         }
   156 
   174     }
   157 private:
   175     return true;
   158     QMap<QString, HbOffsetItem> _mapItems;
   176 }
   159     QByteArray _cssNameBuffer;
   177 
   160 };
   178 /*!
   161 
   179     Collects and return layout names from \a styleRules.
   162 struct InputFile
   180     \a layoutSet - map of already found layoutnames and sections to prevent duplicate layouts
   163 {
   181     to be added.
   164     InputFile(const QString &cacheName, const QFileInfo &file) : cacheName(cacheName), file(file)
   182 
   165     {
   183 */
   166     }
   184 QList<CSSLayoutInfo> collectLayoutNames(
   167 
   185         QSet<QPair<QString, QString> > &layoutSet,
   168     QString cacheName;
   186         const HbVector<HbCss::StyleRule> &styleRules)
   169     QFileInfo file;
   187 {
   170 };
   188     QList<CSSLayoutInfo> layouts;
   171 typedef QList<InputFile> InputFileList;
   189     layouts.append(CSSLayoutInfo());
   172 
   190 
   173 struct InputFileInfo
   191     foreach(const HbCss::StyleRule &rule, styleRules) {
   174 {
   192         foreach(const HbCss::Declaration &decl, rule.declarations) {
   175     QString base;
   193             if (decl.propertyId == HbCss::Property_Layout) {
   176     QString path;
   194                 if (decl.values.count() == 1) {
   177     QString prefix;
   195                     layouts.last().layoutname = decl.values.at(0).variant.toString();
   178 };
   196                 }
   179 typedef QList<InputFileInfo> InputFileInfoList;
   197             } else if (decl.propertyId == HbCss::Property_Section) {
   180 
   198                 if (decl.values.count() == 1) {
   181 bool operator < (const InputFile & if1, const InputFile & if2)
   199                     layouts.last().section = decl.values.at(0).variant.toString();
   182 {
   200                 }
   183     return if1.file.size() > if2.file.size();
   201             }
       
   202         }
       
   203         const CSSLayoutInfo &infoRef = layouts.last();
       
   204         if (!infoRef.layoutname.isEmpty()) {
       
   205             QPair<QString, QString> layout = qMakePair(infoRef.layoutname,
       
   206                                                        infoRef.section);
       
   207             //only add layout, if not already collected before.
       
   208             if (!layoutSet.contains(layout)) {
       
   209                 layoutSet.insert(layout);
       
   210                 layouts.append(CSSLayoutInfo());
       
   211             }
       
   212         }
       
   213     }
       
   214     layouts.removeLast();
       
   215     return layouts;
       
   216 }
       
   217 
       
   218 /*!
       
   219     Collects all the layouts defined in \a stylesheet and add the result to \a input.
       
   220     returns true, if at least one layout is found.
       
   221 */
       
   222 bool collectLayouts(const QString &cssFilePath,
       
   223                     HbCss::StyleSheet *styleSheet,
       
   224                     WidgetMLParseInput &input)
       
   225 {
       
   226     input.clear();
       
   227     QSet<QPair<QString, QString> > layoutSet; //for removing duplicate layout names.
       
   228     foreach(const HbCss::WidgetStyleRules &rule, styleSheet->widgetRules) {
       
   229         layoutSet.clear();
       
   230         input.layouts += collectLayoutNames(layoutSet, rule.styleRules);
       
   231         input.layouts += collectLayoutNames(layoutSet, rule.portraitRules);
       
   232         input.layouts += collectLayoutNames(layoutSet, rule.landscapeRules);
       
   233     }
       
   234     bool hasLayoutDef = false;
       
   235     if (!input.layouts.isEmpty()) {
       
   236         //if css contains at least 1 layout declaration, it might have .widgetml file.
       
   237         QString filePath(cssFilePath);
       
   238         filePath.replace(filePath.size() - CSSFileExtension.size(),
       
   239                          CSSFileExtension.size(), WMLFileExtension);
       
   240         input.filename = filePath;
       
   241         hasLayoutDef = true;
       
   242     }
       
   243     return hasLayoutDef;
   184 }
   244 }
   185 
   245 
   186 void printHelp()
   246 void printHelp()
   187 {
   247 {
   188     out << AppName << " usage:\n\n";
   248     out << AppName << " usage:\n\n";
   204         }
   264         }
   205     }
   265     }
   206     return collected;
   266     return collected;
   207 }
   267 }
   208 
   268 
   209 InputFileList collectCssFiles(const QStringList &inputFilePaths)
   269 QMap<QString, QFileInfo> collectCssFiles(const QStringList &inputFilePaths)
   210 {
   270 {
   211     QStringList filters;
   271     QStringList filters;
   212     filters << "*.css";
   272     filters << "*.css";
   213 
   273 
   214     InputFileList inputFiles;
   274     QMap<QString, QFileInfo> cssFileMap;
   215     QFileInfoList inputPath;
   275     QFileInfoList inputPath;
   216     inputPath.append(QFileInfo());
   276     inputPath.append(QFileInfo());
   217     Q_FOREACH(const QString &path, inputFilePaths) {
   277     Q_FOREACH(const QString &path, inputFilePaths) {
   218         inputPath[0].setFile(path);
   278         inputPath[0].setFile(path);
   219         QFileInfoList allFiles = collectFiles(inputPath, filters);
   279         QFileInfoList allFiles = collectFiles(inputPath, filters);
   220         Q_FOREACH(const QFileInfo &info, allFiles) {
   280         Q_FOREACH(const QFileInfo &info, allFiles) {
   221             inputFiles.append(InputFile(info.fileName(), info));
   281             QMap<QString, QFileInfo>::const_iterator i = cssFileMap.find(info.fileName());
   222         }
   282             if (i == cssFileMap.end()) {
   223     }
   283                 cssFileMap.insert(info.fileName(), info);
   224     return inputFiles;
   284             } else {
   225 }
   285                 err << "duplicate css filenames found: " << i.value().absoluteFilePath() <<
   226 
   286                        " & " << info.absoluteFilePath();
   227 bool writeCssBinary(const QStringList &inputFiles, const QString &targetFile)
   287             }
       
   288         }
       
   289     }
       
   290     return cssFileMap;
       
   291 }
       
   292 
       
   293 /*!
       
   294     Collects the css files from \a inputFiles, parses them to shared memory, stores
       
   295     offsets to \a offsetMap.
       
   296     returns true on success.
       
   297 */
       
   298 bool parseCss(const QStringList &inputFiles, HbOffsetMapBuilder &offsetMap)
   228 {
   299 {
   229     if (inputFiles.isEmpty()) return false;
   300     if (inputFiles.isEmpty()) return false;
   230     InputFileList cssFiles = collectCssFiles(inputFiles);
   301     QMap<QString, QFileInfo> cssFiles = collectCssFiles(inputFiles);
   231     if (cssFiles.isEmpty()) return false;
       
   232     qSort(cssFiles);
       
   233 
   302 
   234     HbCss::Parser parser;
   303     HbCss::Parser parser;
   235     HbCss::StyleSheet *styleSheet = 0;
   304     HbCss::StyleSheet *styleSheet = 0;
   236     bool success = false;
   305     bool success = false;
   237     CssMap cssMap;
   306     
   238     GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory);
   307     GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory);
   239     Q_FOREACH(const InputFile &inputFile, cssFiles) {
   308     while (!cssFiles.isEmpty()) {
   240         const QFileInfo &file = inputFile.file;
   309         QMap<QString, QFileInfo>::iterator first = cssFiles.begin();
   241         VERBOSE("processing " << file.absoluteFilePath() << "...");
   310         QMap<QString, QFileInfo>::iterator CSSFiles[CSSFileTypeEnd];
   242         success = false;
   311 
   243         int offset = manager->alloc(sizeof(HbCss::StyleSheet));
   312         QString widgetName(first.key());
   244         if (offset >= 0) {
   313         if (widgetName.endsWith(ColorCSSEnding)) {
   245             styleSheet = new (static_cast<char*>(manager->base()) + offset)
   314             //color css file, find the layout css pair.
   246                          HbCss::StyleSheet(HbMemoryManager::SharedMemory);
   315             CSSFiles[ColorCSSFile] = first;
   247             parser.init(file.absoluteFilePath(), true);
   316             widgetName.remove(widgetName.size() - ColorCSSEnding.size(),
   248             success = parser.parse(styleSheet);
   317                               ColorCSSEnding.size());
   249             cssMap.add(inputFile.cacheName, offset);
   318             CSSFiles[CSSFile] = cssFiles.find(widgetName + CSSFileExtension);
   250             VERBOSE("cache key = " << inputFile.cacheName << "...");
   319         } else {
   251         }
   320             //layout css file, find the color css pair.
       
   321             CSSFiles[CSSFile] = first;
       
   322             widgetName.remove(widgetName.size() - CSSFileExtension.size(),
       
   323                               CSSFileExtension.size());
       
   324             CSSFiles[ColorCSSFile] = cssFiles.find(widgetName + ColorCSSEnding);
       
   325         }
       
   326         int offsets[] = {-1, -1};
       
   327 
       
   328         for (int i = 0; i < CSSFileTypeEnd; ++i) {
       
   329             if (CSSFiles[i] != cssFiles.end()) {
       
   330                 const QFileInfo &file = CSSFiles[i].value();
       
   331                 VERBOSE("processing " << file.absoluteFilePath() << "...");
       
   332                 offsets[i] = manager->alloc(sizeof(HbCss::StyleSheet));
       
   333                 if (offsets[i] >= 0) {
       
   334                     styleSheet = new (static_cast<char*>(manager->base()) + offsets[i])
       
   335                                  HbCss::StyleSheet(HbMemoryManager::SharedMemory);
       
   336                     parser.init(file.absoluteFilePath(), true);
       
   337                     success = parser.parse(styleSheet);
       
   338                     VERBOSE("cache key = " << CSSFiles[i].key() << "...");
       
   339                 }
       
   340                 if (success) {
       
   341                     VERBOSELN("ok");
       
   342                 } else {
       
   343                     VERBOSELN("failed");
       
   344                     err << "Failed to parse: " << file.absoluteFilePath() << endl;
       
   345                     break;
       
   346                 }
       
   347             }
       
   348         }
       
   349 
       
   350         const QFileInfo *info = 0;
       
   351         QString tmp;
       
   352         if (CSSFiles[CSSFile] != cssFiles.end()) {
       
   353             tmp = CSSFiles[CSSFile].key();
       
   354             info = &CSSFiles[CSSFile].value();
       
   355         }
       
   356         if (!offsetMap.addWidgetOffsets(widgetName, info, offsets)) {
       
   357             return false;
       
   358         }
       
   359 
       
   360         //remove processed files from the map.
       
   361         cssFiles.erase(CSSFiles[ColorCSSFile]);
       
   362         if (!tmp.isEmpty()) {
       
   363             cssFiles.remove(tmp);
       
   364         }
       
   365     }
       
   366     return success;
       
   367 }
       
   368 
       
   369 /*!
       
   370     Parses widgetml file and all the layouts using the info from \a parseInput for a widget,
       
   371     which hash is \a widgetHash, add offsets to \a offsetMap.
       
   372 */
       
   373 bool parseWidgetML(HbOffsetMapBuilder &offsetMap,
       
   374                    quint32 widgetHash,
       
   375                    const WidgetMLParseInput &parseInput)
       
   376 {
       
   377     HbWidgetLoader loader;
       
   378 
       
   379     VERBOSELN("processing: " << parseInput.filename);
       
   380     QFile file(parseInput.filename);
       
   381     if (!file.open(QFile::ReadOnly | QFile::Text)) {
       
   382         VERBOSELN("unable to open file: " << parseInput.filename);
       
   383         return false;
       
   384     }
       
   385     HbWidgetLoader::LayoutDefinition *layoutDef = 0;
       
   386     int layoutDefOffset = -1;
       
   387     bool success = true;
       
   388 
       
   389     GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory);
       
   390     QList<LayoutItem> layoutInfoList;
       
   391     Q_FOREACH(const CSSLayoutInfo &info, parseInput.layouts) {
       
   392         VERBOSE("layout: " << info.layoutname << ", " << "section: " << info.section << "...");
       
   393 
       
   394         layoutDefOffset = manager->alloc(sizeof(HbWidgetLoader::LayoutDefinition));
       
   395         layoutDef = new(static_cast<char *>(manager->base()) + layoutDefOffset)
       
   396             HbWidgetLoader::LayoutDefinition(HbMemoryManager::SharedMemory);
       
   397         success = loader.loadLayoutDefinition(layoutDef, &file, info.layoutname, info.section);
       
   398 
   252         if (success) {
   399         if (success) {
       
   400             layoutInfoList.append(LayoutItem(&info));
       
   401             layoutInfoList.last().offset = layoutDefOffset;
   253             VERBOSELN("ok");
   402             VERBOSELN("ok");
   254         } else {
   403         } else {
   255             VERBOSELN("failed");
   404             VERBOSELN("failed");
   256             err << "Failed to parse: " << file.absoluteFilePath() << endl;
       
   257             break;
   405             break;
   258         }
   406         }
   259     }
   407         file.seek(0);
   260     if (success) {
   408     }
   261         HbSharedMemoryManager *shared = static_cast<HbSharedMemoryManager*>(manager);
   409     success = offsetMap.addWidgetMLOffsets(parseInput.filename, widgetHash, layoutInfoList);
   262 
   410     return success;
   263         // Create shared cache to shared memory.
   411 }
   264         QByteArray data(cssMap.data());
   412 
   265 
   413 /*!
   266         if (shared->createSharedCache(data.data(), data.size(), cssMap.size())) {
   414     Parse all the widgetmls to shared memory for widget's found in \a offsetMap,
   267 
   415     store the offsets to \a offsetMap.
   268             // Defragment the chunk contents before dumping it in a file
   416 */
   269             int endOffset = HbCssConverterUtils::defragmentChunk();
   417 bool parseWidgetML(HbOffsetMapBuilder &offsetMap)
   270 
   418 {
   271             if (verboseOn) {
   419     QList<HbBinMakerOffsetItem> itemList = offsetMap.items();
   272                 HbSharedCache *cache = shared->cache();
   420     Q_FOREACH(const HbBinMakerOffsetItem &item, itemList) {
   273         
   421         if (item.offsetCSS >= 0) {
   274                 for (int k=0; k<cache->mOffsetItemCount; ++k) {
   422             HbCss::StyleSheet *sheet = HbMemoryUtils::getAddress<HbCss::StyleSheet>(
   275                     HbCss::StyleSheet *sheet = HbMemoryUtils::getAddress<HbCss::StyleSheet>(
   423                 HbMemoryManager::SharedMemory, item.offsetCSS);
   276                         HbMemoryManager::SharedMemory, cache->mOffsetItems[k].offset);
   424             WidgetMLParseInput file;
   277                 
   425             if (collectLayouts(item.name, sheet, file)) {
   278                     QString name(QLatin1String( ((char*)(cache->mOffsetItems)) + cache->mOffsetItems[k].nameOffset));
   426                 parseWidgetML(offsetMap, item.widgetHash, file);
   279 
   427             }
   280                     VERBOSE("Cssmap item ");
   428         }
   281                     VERBOSE(k);
   429     }
   282                     VERBOSE("- name: \"");
   430     return true;
   283                     VERBOSE(name);
   431 }
   284                     VERBOSELN("\"");
   432 
   285 
   433 bool writeCssBinary(const QStringList &inputFiles, const QString &targetFile)
   286                     // Tests the stylesheet offsets and prints info to verbose out
   434 {
   287                     testStyleSheet(sheet);
   435     HbOffsetMapBuilder offsetMap;
   288                 }
   436     if (!(parseCss(inputFiles, offsetMap)
   289             }
   437         && parseWidgetML(offsetMap))) {
   290 
   438         return false;
   291             VERBOSELN("writing the binary file");
   439     }
   292             QFile binFile(targetFile);
   440     GET_MEMORY_MANAGER(HbMemoryManager::SharedMemory);
   293             if (!binFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
   441     HbSharedMemoryManager *shared = static_cast<HbSharedMemoryManager*>(manager);
   294                 err << "failed to open target binary file: " << binFile.fileName() << endl;
   442 
   295                 return false;
   443     // Create shared cache to shared memory.
   296             }
   444     QByteArray data(offsetMap.result());
   297             //int size = shared->size();
   445     bool success = false;
   298             if (binFile.write(static_cast<char*>(manager->base()), endOffset) >= 0) {
   446     if (shared->createSharedCache(data.data(), data.size(), offsetMap.size())) {
       
   447         // Defragment the chunk contents before dumping it in a file
       
   448         int endOffset = HbCssConverterUtils::defragmentChunk();
       
   449         if (verboseOn) testCss();
       
   450 
       
   451         VERBOSELN("writing the binary file");
       
   452         QFile binFile(targetFile);
       
   453         success = binFile.open(QIODevice::WriteOnly | QIODevice::Truncate);
       
   454         if (success) {
       
   455             success = (binFile.write(static_cast<char*>(manager->base()), endOffset) >= 0);
       
   456             if (success) {
   299                 VERBOSELN("Wrote target binary file: " << binFile.fileName());
   457                 VERBOSELN("Wrote target binary file: " << binFile.fileName());
   300             } else {
   458             } else {
   301                 err << "failed to write to target binary file: " << binFile.fileName() << endl;
   459                 err << "failed to write to target binary file: " << binFile.fileName() << endl;
   302             }
   460             }
   303         } else {
   461         } else {
   304             err << "failed to create shared cache." << endl;
   462             err << "failed to open target binary file: " << binFile.fileName() << endl;
   305         }
   463         }
       
   464     } else {
       
   465         err << "failed to create shared cache." << endl;
   306     }
   466     }
   307     return success;
   467     return success;
   308 }
   468 }
   309 
   469 
   310 int main(int argc, char **argv)
   470 int main(int argc, char **argv)
   311 {
   471 {
   312     QCoreApplication app(argc, argv);
   472     QCoreApplication app(argc, argv);
       
   473     int returnValue = 0;
   313 
   474 
   314     if(argc < 3) {
   475     if(argc < 3) {
   315         printHelp();
   476         printHelp();
   316     } else {
   477     } else {
   317         QStringList inputFiles;
   478         QStringList inputFiles;
   333             }
   494             }
   334         }
   495         }
   335         if (targetFile.isEmpty()) {
   496         if (targetFile.isEmpty()) {
   336             err << "target filename needed" << endl << endl;
   497             err << "target filename needed" << endl << endl;
   337             printHelp();
   498             printHelp();
       
   499             returnValue = 1;
   338         } else {
   500         } else {
   339             QString parentDir(QFileInfo(targetFile).absolutePath());
   501             QString parentDir(QFileInfo(targetFile).absolutePath());
   340             if (QDir::current().mkpath(parentDir)) {
   502             if (QDir::current().mkpath(parentDir)) {
   341                 writeCssBinary(inputFiles, targetFile);
   503                 if (!writeCssBinary(inputFiles, targetFile)) {
       
   504                     returnValue = 3;
       
   505                 }
   342             } else {
   506             } else {
   343                 err << "failed to create path: " << parentDir << endl;
   507                 err << "failed to create path: " << parentDir << endl;
   344             }
   508                 returnValue = 2;
   345         }
   509             }
   346     }
   510         }
   347     return 0;
   511     }
   348 }
   512     return returnValue;
   349 
   513 }