Logo Search packages:      
Sourcecode: kdeadmin version File versions

configparser.cpp

/* This file is part of the KDE Linux Kernel Configurator
   Copyright (c) 2001 Malte Starostik <malte@kde.org>

   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public
   License as published by the Free Software Foundation; either
   version 2 of the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.  If not, write to
   the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
*/

// $Id: configparser.cpp,v 1.30 2003/05/16 23:47:27 mhunter Exp $

#include <sys/utsname.h>

#include <qdir.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qregexp.h>

#include <kdebug.h>
#include <kstandarddirs.h>
#include <klocale.h>

#include "configparser.h"

using namespace Config;

const QString &VariableNode::value() const
{
      if (m_value.isEmpty() || m_value[0].latin1() != '$')
            return m_value;
      return Parser::self()->symbol(m_value.mid(1));
}

bool DependencyListNode::hasValue(const QString &value) const
{
      for (QPtrListIterator<VariableNode> it(*m_values); it.current(); ++it)
            if (m_values->current()->value() == value)
                  return true;
      return false;
}

void DefineNode::write(QTextStream &str) const
{
      QString val = m_value->value();
      if (val.isEmpty() || ((m_type == Bool || m_type == Tristate) && val == "n"))
            str << "# " << m_symbol << " is not set" << endl;
      else if (m_type == String) str << m_symbol << "=\"" << val << "\"" << endl;
      else str << m_symbol << "=" << val << endl;
}

void DefineNode::writeHeader(QTextStream &str) const
{
      QString val = m_value->value();
      if (val.isEmpty())
            str << "#undef  " << m_symbol << endl;
      else if (m_type == Bool || m_type == Tristate)
      {
            if (val == "y")
                  str << "#define " << m_symbol << " 1" << endl;
            else if (val == "m")
            {
                  str << "#undef  " << m_symbol << endl;
                  str << "#define " << m_symbol << "_MODULE 1" << endl;
            }
            else str << "#undef  " << m_symbol << endl;
      }
      else if (m_type == Hex) str << "#define " << m_symbol << " 0x" << val << endl;
      else if (m_type == String) str << "#define " << m_symbol << "\"" << val << "\"" << endl;
      else str << "#define " << m_symbol << " (" << val << ")" << endl;
}

void UnsetNode::apply() const
{
      for (QStringList::ConstIterator it = m_symbols.begin();
            it != m_symbols.end(); ++it)
            Parser::self()->unsetSymbol(*it);
}

void InputNode::initialize()
{
      if (m_dependencies)
            m_dependencies->initialize();
      setValue(Parser::self()->symbol(m_symbol));
}

void InputNode::write(QTextStream &str) const
{
      QString val = value();
      if (val.isEmpty() || val == "n")
            str << "# " << m_symbol << " is not set" << endl;
      else
            str << m_symbol << "=" << val << endl;
}

void InputNode::setValue(const QString &value)
{
      if (value.isEmpty() && m_default)
            internalSetValue(m_default->value());
      else
            internalSetValue(value);
}

bool InputNode::isAvailable() const
{
      return !m_dependencies || !m_dependencies->hasValue("n");
}

void BoolInputNode::writeHeader(QTextStream &str) const
{
      if (m_value)
            str << "#define " << symbol() << " 1" << endl;
      else
            str << "#undef  " << symbol() << endl;
}

QString BoolInputNode::value() const
{
      if (isAvailable())
            return m_value ? "y" : "n";
      return "n";
}

void BoolInputNode::internalSetValue(const QString &value)
{
      if (isAvailable() && value == "y")
            m_value = true;
      else
            m_value = false;
}

void BoolInputNode::toggle()
{
      if (isAvailable())
            m_value = !m_value;
      else
            m_value = false;
}

bool RestricedBoolInputNode::isAvailable() const
{
      return !m_dependencies ||
            (!m_dependencies->hasValue("n") && !m_dependencies->hasValue("m"));
}

void IntInputNode::writeHeader(QTextStream &str) const
{
      if (m_value)
            str << "#define " << symbol() << " (" << m_value << ")" << endl;
      else
            str << "#undef  " << symbol() << endl;
}

QString IntInputNode::value() const
{
      return isAvailable() ? QString::number(m_value) : "0";
}

void IntInputNode::internalSetValue(const QString &value)
{
      if (isAvailable())
            m_value = value.toInt();
      else
            m_value = 0;
}

void HexInputNode::writeHeader(QTextStream &str) const
{
      if (m_value)
            str << "#define " << symbol() << " 0x" << value() << endl;
      else
            str << "#undef  " << symbol() << endl;
}

QString HexInputNode::value() const
{
      return isAvailable() ? QString::number(m_value, 16) : "0";
}

void HexInputNode::internalSetValue(const QString &value)
{
      if (isAvailable())
            m_value = value.toInt(0, 16);
      else
            m_value = 0;
}

void StringInputNode::write(QTextStream &str) const
{
      if (m_value.isEmpty())
            InputNode::write(str);
      else
            str << symbol() << "=\"" << m_value << "\"" << endl;
}

void StringInputNode::writeHeader(QTextStream &str) const
{
      if (m_value.isEmpty())
            str << "#undef  " << symbol() << endl;
      else
            str << "#define " << symbol() << " \"" << m_value << "\"" << endl;
}

QString StringInputNode::value() const
{
      return isAvailable() ? m_value : QString::null;
}

void StringInputNode::internalSetValue(const QString &value)
{
      if (isAvailable())
            m_value = value;
      else
            m_value = QString::null;
}

void TristateInputNode::writeHeader(QTextStream &str) const
{
      switch (m_value)
      {
            case No:
                  str << "#undef  " << symbol() << endl;
                  break;
            case Yes:
                  str << "#define " << symbol() << " 1" << endl;
                  break;
            case Module:
                  str << "#undef  " << symbol() << endl;
                  str << "#define " << symbol() << "_MODULE 1" << endl;
                  break;
      }
}

QString TristateInputNode::value() const
{
      if (isAvailable())
            switch (m_value)
            {
                  case No:
                        return "n";
                  case Yes:
                        if (m_dependencies && m_dependencies->hasValue("m"))
                              return "m";
                        return "y";
                  case Module:
                        return "m";
            }
      return "n";
}

void TristateInputNode::internalSetValue(const QString &value)
{
      if (isAvailable())
      {
            if (value == "y")
            {
                  if (m_dependencies && m_dependencies->hasValue("m"))
                        m_value = Module;
                  else
                        m_value = Yes;
            }
            else if (value == "m")
                  m_value = Module;
            else
                  m_value = No;
      }
      else
            m_value = No;
      if (m_value == Module && Parser::self()->symbol("CONFIG_MODULES") != "y")
            m_value = Yes;
}

void TristateInputNode::advance()
{
      if (isAvailable())
      {
            switch (m_value)
            {
                  case No:
                        m_value = Module;
                        break;
                  case Yes:
                        m_value = No;
                        break;
                  case Module:
                        if (m_dependencies && m_dependencies->hasValue("m"))
                              m_value = No;
                        else
                              m_value = Yes;
                        break;
            }
      }
}

void ChoiceNode::initialize()
{
      m_index = m_defaultIndex;
      int i = 0;
      for (QStringList::ConstIterator it = m_symbols.begin();
            it != m_symbols.end();
            ++it, ++i)
            if (Parser::self()->symbol(*it) == "y")
                  m_index = i;
}

void ChoiceNode::apply() const
{
      int i = 0;
      for (QStringList::ConstIterator it = m_symbols.begin();
            it != m_symbols.end();
            ++it, ++i)
            Parser::self()->setSymbol(*it, i == m_index ? "y" : "n");
}

void ChoiceNode::write(QTextStream &str) const
{
      int i = 0;
      for (QStringList::ConstIterator it = m_symbols.begin();
            it != m_symbols.end();
            ++it, ++i)
            if (i == m_index)
                  str << *it << "=y" << endl;
            else
                  str << "# " << *it << " is not set" << endl;
}

void ChoiceNode::writeHeader(QTextStream &str) const
{
      int i = 0;
      for (QStringList::ConstIterator it = m_symbols.begin();
            it != m_symbols.end();
            ++it, ++i)
            if (i == m_index)
                  str << "#define " << *it << " 1" << endl;
            else
                  str << "#undef  " << *it << endl;
}

void BranchNodeBase::initialize()
{
      NodeList *kids = children();
      if (kids)
            for (kids->first(); kids->current(); kids->next())
                  kids->current()->initialize();
}

void BranchNodeBase::apply() const
{
      NodeList *kids = children();
      if (kids)
            for (kids->first(); kids->current(); kids->next())
                  kids->current()->apply();
}

void BranchNodeBase::write(QTextStream &str) const
{
      NodeList *kids = children();
      if (kids)
            for (kids->first(); kids->current(); kids->next())
                  kids->current()->write(str);
}

void BranchNodeBase::writeHeader(QTextStream &str) const
{
      NodeList *kids = children();
      if (kids)
            for (kids->first(); kids->current(); kids->next())
                  kids->current()->writeHeader(str);
}

void RootNode::write(QTextStream &str) const
{
      str << "#" << endl;
      str << "# Automatically generated by kcmlinuz: don't edit" << endl;
      str << "#" << endl;
      BranchNodeBase::write(str);
}

void RootNode::writeHeader(QTextStream &str) const
{
      str << "/*" << endl;
      str << " * Automatically generated by kcmlinuz: don't edit" << endl;
      str << " */" << endl;
      str << "#define AUTOCONF_INCLUDED" << endl;
      BranchNodeBase::writeHeader(str);
}

void MenuNode::write(QTextStream &str) const
{
      str << endl;
      str << "#" << endl;
      str << "# " << m_comment->text() << endl;
      str << "#" << endl;
      BranchNodeBase::write(str);
}

void MenuNode::writeHeader(QTextStream &str) const
{
      str << endl;
      str << "/*" << endl;
      str << " * " << m_comment->text() << endl;
      str << " */" << endl;
      BranchNodeBase::writeHeader(str);
}

void IfNode::initialize()
{
      NodeList *kids = m_trueChildren;
      if (kids)
            for (kids->first(); kids->current(); kids->next())
                  kids->current()->initialize();
      kids = m_falseChildren;
      if (kids)
            for (kids->first(); kids->current(); kids->next())
                  kids->current()->initialize();
}

extern int linuzparse();

Parser *Parser::s_self = 0;

Parser::Parser()
      : m_root(0)
{
      s_self = this;
      m_ruleStack.setAutoDelete(true);

      m_kernelRoot = "/usr/src/linux"; // Default kernel source tree

      struct utsname info;
      uname(&info); // Determine architecture default from uname()
      m_arch = info.machine;
      if (QRegExp("i.86").search(m_arch) != -1)
            m_arch = "i386";
      else if (m_arch == "sun4u")
            m_arch = "sparc64";
      else if (QRegExp("arm.*").search(m_arch) != -1)
            m_arch = "arm";
      else if (m_arch == "sa110")
            m_arch = "arm";
}

Parser::~Parser()
{
      delete m_root;
      s_self = 0;
}

QStringList Parser::availableArchs(const QString &root) const
{
      QDir dir(QString::fromLatin1("%1/arch").arg(root));
      QStringList archs = dir.entryList(QDir::Dirs);
      for (QStringList::Iterator it = archs.begin(); it != archs.end(); )
      {
            if (*it == "." || *it == "..")
                  archs.remove(it++);
            else
                  ++it;
      }
      return archs;
}

bool Parser::parseConfig(const QString &kernelRoot, const QString &arch)
{
      delete m_root;
      m_root = 0;
      m_symbols.clear();
      m_errors.clear();
      m_kernelRoot = kernelRoot;
      m_arch = arch;
      setSymbol("ARCH", arch);
      if (m_arch.isNull())
      {
            addError(i18n("No hardware architecture was specified! "
                              "Perhaps the kernel source code is not installed on this system, "
                              "or the path to the kernel sources is entered incorrectly."));
      }
      else if (pushInclude(QString::fromLatin1("arch/%1/config.in").arg(m_arch)))
      {
            linuzparse();
      }
      else if (QFileInfo(kernelRoot+QString::fromLatin1("/arch/%1/Kconfig").arg(m_arch)).exists())
      {
            addError(i18n("Linux kernel versions 2.5 and above are not yet"
                              " supported."));
      }
      m_ruleStack.clear();
      return m_errors.count() == 0;
}

void Parser::setRoot(RootNode *root)
{
      delete m_root;
      m_root = root;
}

const QString &Parser::symbol(const QString &name) const
{
      SymbolTable::ConstIterator found = m_symbols.find(name);
      return (found == m_symbols.end()) ? QString::null : *found;
}

void Parser::setSymbol(const QString &name, const QString &value)
{
      m_symbols[name] = value;
}

void Parser::unsetSymbol(const QString &name)
{
      m_symbols.remove(name);
}

bool Parser::readConfig(const QString &file)
{
      m_symbols.clear();
      setSymbol("ARCH", m_arch);
      QFile f(file);
      if (!f.open(IO_ReadOnly))
            return false;
      QTextStream str(&f);
      while (!str.atEnd())
      {
            QString line = str.readLine().simplifyWhiteSpace();
            if (line.isEmpty() || line[0].latin1() == '#')
            {
                  if (line.right(11) == " is not set")
                        setSymbol(line.mid(2, line.length() - 13), "n");
                  continue;
            }
            int p = line.find("=");
            if (p == -1)
                  continue;
            QString name = line.left(p);
            QString value = line.mid(p + 1);
            if (value[0] == '"' && value[value.length() - 1] == '"')
                  value = value.mid(1, value.length() - 2);
            setSymbol(name, value);
      }
      if (m_root)
            m_root->initialize();
      return true;
}

bool Parser::writeConfig(const QString &file) const
{
      QFile f(file);
      if (!f.open(IO_WriteOnly))
            return false;
      QTextStream str(&f);
      m_root->write(str);
      return true;
}

bool Parser::writeHeader(const QString &file) const
{
      QFile f(file);
      if (!f.open(IO_WriteOnly))
            return false;
      QTextStream str(&f);
      m_root->writeHeader(str);
      return true;
}

void Parser::apply() const
{
      m_root->apply();
}

void Parser::makeHTMLLinks(QString &text, const QString &regexp,
      const QString &prefix) const
{
      QRegExp urlRex(regexp.latin1());
      int match;
      for (unsigned int start = 0; (match = urlRex.search(text, start)) >= 0; )
      {
            QString link = QString::fromLatin1("<a href=\"%1%2\">%3</a>")
                        .arg(prefix)
                        .arg(urlRex.cap(0))
                        .arg(urlRex.cap(0));
            text.replace(match, urlRex.matchedLength(), link);
            start = match + link.length();
            if (start >= text.length())
                  break; // Don't crash
      }
}

QString Parser::helpText(const QString &symbol)
{
      if (!m_help.count())
      {
            QFile f(QString::fromLatin1("%1/Documentation/Configure.help")
                  .arg(m_kernelRoot));
            if (f.open(IO_ReadOnly))
            {
                  QTextStream str(&f);
                  for (QString line = str.readLine(); !line.isNull(); line = str.readLine())
                        m_help.append(line);
            }

            QFile tpl(locate("data", "kcmlinuz/data/help-template.html"));
            if (tpl.open(IO_ReadOnly))
            {
                  QTextStream str(&tpl);
                  m_helpTemplate = str.read();
            }
            else
                  m_helpTemplate = QString::fromLatin1(
                        "<html><head></head><body>"
                        "<h1>{TITLE}</h1><h2>{SYMBOL}</h2>"
                        "<p>{CONTENTS}</p>"
                        "</body></html>");
      }
      QString title;
      QString contents;
      for (QStringList::ConstIterator it = m_help.find(symbol);
            it != m_help.end();
            ++it)
      {
            if (title.isEmpty())
            {
                  title = *(--it);
                  it++;
            }
            else if ((*it).isEmpty())
                  contents += "\n";
            else if (!(*it).startsWith("  "))
                  break;
            else
                  contents += *it;
      }
      if (contents.isEmpty())
            return QString::null;

      // Order is important here
      contents.replace(QRegExp("&"), "&amp;");
      contents.replace(QRegExp("<"), "&lt;");
      contents.replace(QRegExp(">"), "&gt;");

      makeHTMLLinks(contents, "(http|ftp)://[^ \t\n&]+[^ \t\n\\.,()&]");
      makeHTMLLinks(contents, "[A-Za-z0-9_\\.+-]+@[A-Za-z0-9_\\.-]+[A-Za-z0-9_-]", "mailto:");
      makeHTMLLinks(contents, "Documentation/[^ \t\n&]+[^ \t\n\\.,()&]",
            QString::fromLatin1("file:/%1/").arg(m_kernelRoot));

      contents.replace(QRegExp("\n"), "</p><p>");

      QString result = m_helpTemplate;
      result.replace(QRegExp("\\{TITLE\\}"), title);
      result.replace(QRegExp("\\{SYMBOL\\}"), symbol);
      result.replace(QRegExp("\\{CONTENTS\\}"), contents);
      return result;
}

RuleFile::RuleFile(const QString &file)
      : m_line(1),
        m_column(0),
        m_buffer(0)
{
      QFile f(m_name = QString::fromLatin1("%1/%2")
            .arg(Parser::self()->kernelRoot())
            .arg(file));
      if (f.open(IO_ReadOnly))
      {
            QTextStream str(&f);
            m_data = str.read();
      }
      else
            Parser::self()->addError(i18n("cannot open %1 for reading").arg(m_name));
}

QString RuleFile::currentLine() const
{
      int pos = -1;
      for (int i = 0; i < m_line - 1; ++i)
            if ((pos = m_data.find("\n", ++pos)) == -1)
                  return QString::null;
      int len = m_data.find("\n", ++pos);
      return m_data.mid(pos, len != -1 ? len - pos : -1);
}

ErrorInfo::ErrorInfo(const QString &message)
      : m_message(message)
{
      RuleFile *rule = Parser::self()->currentFile();
      if (rule)
      {
            m_file = rule->name();
            m_text = rule->currentLine();
            m_line = rule->line();
            m_pos = rule->pos() - rule->tokenLength();
            m_length = rule->tokenLength();
      }
}

// vim: ts=4 sw=4 noet

Generated by  Doxygen 1.6.0   Back to index