Logo Search packages:      
Sourcecode: paco version File versions  Download package

info.cc

//=======================================================================
// info.cc
//-----------------------------------------------------------------------
// This file is part of the package paco
// Copyright (C) 2004-2009 David Rosal
// For more information visit http://paco.sourceforge.net
//=======================================================================

#include "config.h"
#include "global.h"
#include "info.h"
#include "log.h"
#include "pkg.h"
#include "regexp.h"
#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <string>
#include <glob.h>

using std::endl;
using std::string;
using std::vector;
using std::set;
using namespace Paco;


// Forward declarations
static string getVar(string const&, string const&);
static string getBuildVar(string const&);
static string stripTrailingDot(string const&);


Info::Info(Log& log)
:
      mIcon(),
      mOpts(),
      mName(),
      mVersion(),
      mAuthor(),
      mSummary(),
      mUrl(),
      mLicense(),
      mDesc(),
      mPkg(log.mPkgName),
      mBase(Pkg::getBase(mPkg)),
      mDesktopFile(),
      mDef(),
      mDirs(),
      mFiles(log.mFiles)
{
      gOut.dbgTitle("information");

      getDirs();

      mDesktopFile = searchFile(mBase, ".desktop");

      mIcon = getIcon();
      getInfoSpec();
      getInfoAspec();
      getInfoPC();
      getInfoDesktop();
      getConfigOpts();

      if (mName.empty())
            mName = mBase;
      if (mVersion.empty())
            mVersion = Pkg::getVersion(mPkg);

      writeInfo();

      if (gOut.verbosity() > Out::VERBOSE)
            printInfo();
}


Info::Define::Define(char const fmt, string const& var, string const& val)
:
      mFmt(fmt),
      mVar(var),
      mVal(val)
{ }


void Info::Define::resolve(string& str) const
{
      if (str.find(mFmt) == string::npos)
            return;
                  
      string::size_type p;
      string var0(1, mFmt);
      string var1(1, mFmt);
      var0 += mVar;
      var1 += "{" + mVar + "}";

      for (p = 0; (p = str.find(var0, p)) != string::npos; )
            str.replace(p, var0.size(), mVal);
      for (p = 0; (p = str.find(var1, p)) != string::npos; )
            str.replace(p, var1.size(), mVal);
}


string& Info::resolveDefines(string& str) const
{
      for (uint i = 0; i < mDef.size(); ++i)
            mDef[i].resolve(str);
      return str;
}


void Info::getSpecDefines(string const& spec)
{
      std::ifstream f(spec.c_str());
      if (!f)
            return;
            
      char* var;
      char* p;
      char* val;
      char buf[8192];

      while (!f.getline(buf, sizeof(buf)).eof()) {
            if ((p = strtok(buf, " \t")) && !strcmp(p, "%define")
            &&    (var = strtok(NULL, " \t\n"))
            &&    (val = strtok(NULL, " \t\n")) && val[0] != '%')
                  mDef.push_back(Define(Define::FMT_SPEC, var, val));
      }
}


void Info::getPCDefines(string const& pc)
{
      std::ifstream f(pc.c_str());
      if (!f)
            return;
            
      string buf;
      string::size_type p;

      while (getline(f, buf)) {
            if ((p = buf.find("=")) != string::npos && buf.size() > p)
                  mDef.push_back(Define(Define::FMT_PC, buf.substr(0, p), buf.substr(p + 1)));
      }
}


bool Info::getInfoVar(string const& file, string const& tag, string& info) const
{
      if (!info.empty())
            return true;

      std::ifstream f(file.c_str());
      if (!f)
            return false;
            
      string buf;
      string::size_type p;

      // avoid @foo@, %{foo} and ${foo}
#if HAVE_REGEX_H
      Regexp re("(^@.*@$|%\\{.*\\}|\\$\\{.*\\})");
#endif
      
      while (getline(f, buf) && info.empty()) {
            if (!buf.find(tag) && (p = buf.find_first_not_of(" \t:=", tag.size())) != string::npos) {
                  buf.erase(0, p);
                  resolveDefines(buf);
#if HAVE_REGEX_H
                  if (!re.run(buf))
                        info = buf;
#endif
            }
      }

      return !info.empty();
}


void Info::getDescription(string const& spec, string const& title)
{
      if (!mDesc.empty())
            return;

      std::ifstream f(spec.c_str());
      if (!f)
            return;
      
      string buf;

      while (getline(f, buf) && buf.find(title) != 0) ;
      if (f.eof())
            return;
      
      bool emptyLine = false;
      
      while (getline(f, buf) && buf[0] != title[0] && buf[0] != '#') {
            if (buf.empty()) {
                  if (!emptyLine && !mDesc.empty())
                        mDesc += "\n#:";
                  emptyLine = true;
            }
            else {
                  mDesc += resolveDefines(buf) + (buf.size() < 48 ? "\n#:" : " ");
                  emptyLine = false;
            }
      }
      
      if (mDesc.size() < 8)
            mDesc.clear();
}


void Info::getInfoAspec()
{
      string aspec(searchFile(mBase, ".aspec"));
      if (aspec.empty())
            return;

      getInfoVar(aspec, "ShortName", mName);
      getInfoVar(aspec, "PackageVersion", mVersion);
      getInfoVar(aspec, "URL", mUrl);
      getInfoVar(aspec, "License", mLicense);
      getDescription(aspec, "[Description]");
      if (!getInfoVar(aspec, "Maintainer", mAuthor))
            getInfoVar(aspec, "Packager", mAuthor);
      if (!getInfoVar(aspec, "Summary", mSummary))
            getInfoVar(aspec, "DisplayName", mSummary);
}


void Info::getInfoSpec()
{
      string spec(searchFile(mBase, ".spec"));
      if (spec.empty())
            return;

      getSpecDefines(spec);

      getInfoVar(spec, "Name", mName);
      getInfoVar(spec, "Version", mVersion);
      getInfoVar(spec, "Summary", mSummary);
      getInfoVar(spec, "URL", mUrl);
      getInfoVar(spec, "Icon", mIcon);
      getDescription(spec, "%description");
      if (!getInfoVar(spec, "Vendor", mAuthor))
            getInfoVar(spec, "Packager", mAuthor);
      if (!getInfoVar(spec, "License", mLicense))
            getInfoVar(spec, "Copyright", mLicense);
}


void Info::getInfoDesktop()
{
      if (mDesktopFile.empty())
            return;
      getInfoVar(mDesktopFile, "Name", mName);
      if (!getInfoVar(mDesktopFile, "Comment", mSummary))
            getInfoVar(mDesktopFile, "GenericName", mSummary);
}


void Info::getInfoPC()
{
      string pc(searchFile(mBase, ".pc"));
      if (pc.empty())
            return;

      getPCDefines(pc);
      
      getInfoVar(pc, "Name", mName);
      getInfoVar(pc, "Version", mVersion);
      getInfoVar(pc, "Description", mSummary);
}


string Info::searchFile(string const& name, string const& suffix /* = "" */) const
{
      if (name.empty())
            return name;

      gOut.dbg("searching " + name + suffix);
      
      glob_t g;
      memset(&g, 0, sizeof(g));
      
      string file, pat[2] = { "*/*/" + name + suffix,
                                          "*/*/" + name + "-[0-9]*" + suffix };

      for (uint i = 0; i < 2; ++i) {
            for (set<string>::iterator d = mDirs.begin(); d != mDirs.end(); ++d) {
                  for (int k = 2; k >= 0; --k) {
                        string s = *d + "/" + pat[i].substr(k << 1);
                        if (!glob(s.c_str(), GLOB_NOSORT, 0, &g) && g.gl_pathc) {
                              file = g.gl_pathv[0];
                              goto ____return;
                        }
                  }
            }
      }
      
____return:
      globfree(&g);

      if (file.empty())
            gOut.dbg("\t(not found)\n", false);
      else
            gOut.dbg("\t" + file + "\n", false);
            
      return file;
}


void Info::getConfigOpts()
{
      if (!mOpts.empty())
            return;

      string configLog(searchFile("config.log"));
      if (configLog.empty())
            return;

      std::ifstream f(configLog.c_str());
      if (!f)
            return;

      string buf;
      string::size_type p;

      while (getline(f, buf) && mOpts.empty()) {
            if ((p = buf.find("$")) != string::npos
            &&    (p = buf.find("/configure", p)) != string::npos
            &&    (p = buf.find("--", p)) != string::npos)
                  mOpts = buf.substr(p);
      }
}


string Info::getIcon()
{
      string exp(".(png|xpm|jpg|ico|gif|svg)$");

      // First search for the name of the icon in the .desktop file
      string icon = getVar(mDesktopFile, "Icon");
#if HAVE_REGEX_H
      if (!icon.empty()) {
            Regexp re1(exp);
            if (!re1.run(icon))
                  icon.clear();
      }
#endif

      // If the icon was not found in the desktop file, search for the base name
      // of the package.
      if (icon.empty())
            exp = "/" + mBase + exp;
      else {
            exp = "/" + icon + "$";
            icon.clear();
      }

      // Search the logged files for the path of the icon
#if HAVE_REGEX_H
      Regexp re2(exp, true);
      for (set<string>::iterator i = mFiles.begin(); i != mFiles.end(); ++i) {
            if (re2.run(*i)) {
                  icon = *i;
                  break;
            }
      }
#endif

      return icon;
}


void Info::getDirs()
{
      mDirs.insert(".");

      string dir;
      if ((dir = getBuildVar("top_srcdir")).size())
            mDirs.insert(dir);
      if ((dir = getBuildVar("top_builddir")).size())
            mDirs.insert(dir);
}


void Info::writeInfo() const
{
      FileStream<std::ofstream> f(Config::logdir() + "/" + mPkg);

      f << "#!paco-" PACKAGE_VERSION "\n#d:" << time(0) << "\n";

      if (!mOpts.empty())
            f << "#c:" << mOpts << "\n";
      if (!mIcon.empty())
            f << "#i:" << mIcon << "\n";
      if (!mName.empty())
            f << "#:Name:     " << mName << "\n";
      if (!mVersion.empty())
            f << "#:Version:  " << mVersion << "\n";
      if (!mAuthor.empty())
            f << "#:Author:   " << mAuthor << "\n";
      if (!mSummary.empty())
            f << "#:Summary:  " << stripTrailingDot(mSummary) << "\n";
      if (!mUrl.empty())
            f << "#:URL:      " << mUrl << "\n";
      if (!mLicense.empty())
            f << "#:License:  " << mLicense << "\n";
      if (!mDesc.empty())
            f << "#:\n#:Description\n#:" << mDesc << "\n";
}


void Info::printInfo() const
{
      gOut.dbgTitle("");
      gOut.dbg("Name:        " + mName + "\n");
      gOut.dbg("Version:     " + mVersion + "\n");
      gOut.dbg("Author:      " + mAuthor + "\n");
      gOut.dbg("Summary:     " + mSummary + "\n");
      gOut.dbg("URL:         " + mUrl + "\n");
      gOut.dbg("License:     " + mLicense + "\n");
      gOut.dbg("Conf. opts:  " + mOpts + "\n");
      gOut.dbg("Icon:        " + mIcon + "\n");
      gOut.dbg("Description: ");
      std::ostringstream s;
      if (!mDesc.empty())
            s << "(" << mDesc.size() << " chars written)";
      gOut.dbg(s.str() + "\n", false);
      gOut.dbgTitle("");
}


static string getVar(string const& file, string const& tag)
{
      std::ifstream f(file.c_str());
      if (!f)
            return "";
      
      string::size_type p;
      string buf;
      string var;

      while (getline(f, buf) && var.empty()) {
            if (!buf.find(tag) && (p = buf.find_first_not_of(" =\t\n", tag.size())) != string::npos)
                  var = buf.substr(p);
      }

      return var;
}


//
// Extract the value of 'var' from Makefile, makefile or config.log
//
static string getBuildVar(string const& var)
{
      string v = getVar("Makefile", var);
      if (v.empty())
            v = getVar("makefile", var);
      if (v.empty())
            v = getVar("config.log", var);

      return v;
}


static string stripTrailingDot(string const& s)
{
      if (s.size() && s.at(s.size() - 1) == '.')
            return s.substr(0, s.size() - 1);
      return s;
}



Generated by  Doxygen 1.6.0   Back to index