<commit_before>/**************************************************************************
**
** This file is part of Doxygen plugin for Qt Creator
**
** Copyright (c) 2009 Kevin Tanguy (kofee@kofee.org).
**
** This plugin is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as
** published by the Free Software Foundation, either version 2.1
** of the License, or (at your option) any later version.
**
** This plugin 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Doxygen Plugin. If not, see <http://www.gnu.org/licenses/>.
**/

#include "doxygen.h"

#include <QObject>
#include <plugins/cppeditor/cppeditorconstants.h>
#include <plugins/cpptools/cpptoolsconstants.h>
#include <plugins/cpptools/cppmodelmanagerinterface.h>
#include <plugins/texteditor/basetexteditor.h>
#include <plugins/coreplugin/icore.h>
#include <plugins/coreplugin/uniqueidmanager.h>
#include <plugins/coreplugin/mimedatabase.h>
#include <plugins/coreplugin/actionmanager/actionmanager.h>
#include <plugins/coreplugin/editormanager/ieditor.h>
#include <plugins/coreplugin/editormanager/editormanager.h>
#include <plugins/projectexplorer/project.h>
#include <plugins/projectexplorer/projectexplorer.h>
#include <plugins/projectexplorer/session.h>
#include <plugins/projectexplorer/projectexplorerconstants.h>

#include <libs/cplusplus/Overview.h>
#include <libs/extensionsystem/pluginmanager.h>
#include <shared/cplusplus/Scope.h>
#include <shared/cplusplus/Symbols.h>
#include <shared/cplusplus/Names.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/CppBindings.h>

#include <QString>
#include <QStringList>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QRegExp>

using namespace CPlusPlus;
using namespace ProjectExplorer;
using namespace DoxyPlugin;
using namespace DoxyPlugin::Internal;

Doxygen* Doxygen::m_instance = 0;

Doxygen::Doxygen()
{
}

Doxygen* Doxygen::instance()
{
    if (!m_instance)
        m_instance = new Doxygen();
    return m_instance;
}

// TODO, get rid of it.
QStringList scopesForSymbol(const Symbol* symbol)
{
    Scope *scope = symbol->scope();
    QStringList scopes;

    if(symbol->isFunction())
    {
        const Name *name = symbol->name();
        Overview overview;
        overview.setShowArgumentNames(false);
        overview.setShowReturnTypes(false);
        scopes.prepend(overview.prettyName(name));
        return scopes;
    }

    for (; scope; scope = scope->enclosingScope())
    {
        Symbol *owner = scope->owner();

        if (owner && owner->name() && ! scope->isEnumScope())
        {
            const Name *name = owner->name();
            Overview overview;
            overview.setShowArgumentNames(false);
            overview.setShowReturnTypes(false);
            scopes.prepend(overview.prettyName(name));
        }
    }
    return scopes;
}

Symbol* currentSymbol(Core::IEditor *editor)
{
    int line = editor->currentLine();
    int column = editor->currentColumn();

    CppTools::CppModelManagerInterface *modelManager =
            ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
    if (!modelManager)
        return 0;
    const Snapshot snapshot = modelManager->snapshot();
    Document::Ptr doc = snapshot.document(editor->file()->fileName());
    if (!doc)
        return 0;
    return doc->findSymbolAt(line, column);
}

// TODO, recode it entirely.
void Doxygen::createDocumentation(const DoxygenSettingsStruct &DoxySettings)
{
    const Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    // before continuing, test if the editor is actually showing a file.
    if(!editor) return;

    // get the widget for later.
    TextEditor::BaseTextEditor *editorWidget = qobject_cast<TextEditor::BaseTextEditor*>(
            editorManager->currentEditor()->widget());

    // TODO, only do that if class and verbosePrinting
    // Catch hold of the plugin-manager
    ExtensionSystem::PluginManager* pm
            = ExtensionSystem::PluginManager::instance();
    // Look for the ProjectExplorerPlugin object
    ProjectExplorer::ProjectExplorerPlugin* projectExplorerPlugin
            = pm->getObject<ProjectExplorer::ProjectExplorerPlugin>();
    // Fetch a list of all open projects
    QList<ProjectExplorer::Project*> projects
            = projectExplorerPlugin->session()->projects();
    // Project root directory
    QString projectRoot;

    // Attempt to find our project
    Q_FOREACH(ProjectExplorer::Project* project, projects)
    {
        QStringList files = project->files(Project::ExcludeGeneratedFiles); // ProjectExplorer::Project::FilesMode::ExcludeGeneratedFiles
        // is it our project ?
        if(files.contains(editor->file()->fileName()))
        {
            // YES! get the .pro and remove the directory part from our filename
            // TODO, check if it is smart... (it's not really.)
            Q_FOREACH(QString f, files)
            {
                if(f.contains(QRegExp(".pro$")))
                {
                    projectRoot = f.section('/', 0, -2);
                    if(projectRoot.size()) projectRoot.append("/");
                    continue;
                }
            }
            if(projectRoot.size()) continue;
        }
    }

    Symbol *lastSymbol = currentSymbol(editor);
    if (!lastSymbol || !lastSymbol->scope())
        return;

    QStringList scopes = scopesForSymbol(lastSymbol);
    Overview overview;
    overview.setShowArgumentNames(true);
    overview.setShowReturnTypes(true);
    overview.setShowFullyQualifiedNamed(true);
    overview.setShowFunctionSignatures(true);
    const Name *name = lastSymbol->name();
    scopes.append(overview.prettyName(name));

    QString docToWrite;

    // Do we print a short documentation block at end of line?
    bool printAtEnd = false;

    // Get current indentation as per bug #5
    QString indent;
    editorWidget->moveCursor(QTextCursor::StartOfLine);
    editorWidget->gotoLineEndWithSelection();
    QString currentText = editorWidget->textCursor().selectedText();
    QStringList textList = currentText.split(QRegExp("\\b"));
    indent = textList.at(0);
    if(indent.endsWith('~'))
    {
        indent.chop(1);
    }

    if(lastSymbol->isClass())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }
        if(DoxySettings.verbosePrinting)
        {
            QString fileName = editor->file()->fileName().remove(0, editor->file()->fileName().lastIndexOf("/") + 1);
            QString fileNameProj = editor->file()->fileName().remove(projectRoot);
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "class " + overview.prettyName(name) + " " + fileName + " \"" + fileNameProj + "\"\n";
        }
        docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
    }
    else if(lastSymbol->isTypedef())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }
        if(DoxySettings.verbosePrinting)
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "typedef " + overview.prettyName(name);
        docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
    }
    else if(lastSymbol->isEnum())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
        docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        if(DoxySettings.verbosePrinting)
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "enum " + overview.prettyName(name) + "\n";
        docToWrite += DoxySettings.DoxyComment.doxEnding;
    }
    // Here comes the bitch.
    else if(lastSymbol->isDeclaration() || lastSymbol->isFunction())
    {
        overview.setShowArgumentNames(true);
        overview.setShowReturnTypes(false);
        overview.setShowFullyQualifiedNamed(true);
        overview.setShowFunctionSignatures(true);
        QString arglist = overview.prettyType(lastSymbol->type(), name);

        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }

        // if variable, do it quickly...
        if(!arglist.contains('('))
        {
            if(DoxySettings.shortVarDoc)
            {
                printAtEnd = true;
                docToWrite = DoxySettings.DoxyComment.doxShortVarDoc + "TODO */";
            }
            else
            {
                if(DoxySettings.verbosePrinting)
                    docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "var " + overview.prettyName(name) + "\n" + indent + DoxySettings.DoxyComment.doxEnding;
                else
                    docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine + indent + DoxySettings.DoxyComment.doxEnding;
            }
        }
        else
        {
            // Never noticed it before, a useless comment block because of the Q_OBJECT macro
            // so let's just ignore that will we?
            if(overview.prettyName(name) == "qt_metacall")
                return;

            if(DoxySettings.verbosePrinting)
                docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "fn " + overview.prettyName(name) + "\n";

            // Check parameters
            // Do it the naive way first before finding better in the API
            arglist.remove(0, arglist.indexOf("(") + 1);
            arglist.remove(arglist.lastIndexOf(")"), arglist.size() - arglist.lastIndexOf(")"));
            int indexfrom, indexto;
            while( ((indexfrom = arglist.indexOf('<'))!= -1) && (indexto = arglist.indexOf('>') != -1) )
            {
                    arglist.remove(indexfrom, indexto - indexfrom + 1);
            }
            QStringList args = arglist.trimmed().split(',', QString::SkipEmptyParts);

            Q_FOREACH(QString singleArg, args)
            {
                singleArg.remove(QRegExp("\\s*=.*")); // FIXME probably don't need the * after \\s but...
                singleArg.replace("*","");
                singleArg.replace("&","");
                docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "param " + singleArg.section(' ',  -1) + "\n";
            }

            // And now check the return type
            overview.setShowArgumentNames(false);
            overview.setShowReturnTypes(true);
            overview.setShowFullyQualifiedNamed(false);
            overview.setShowFunctionSignatures(false);

            arglist = overview.prettyType(lastSymbol->type(), name);

            // FIXME this check is just insane...
            if( arglist.contains(' ') && (((overview.prettyName(name) != scopes.front()) && (overview.prettyName(name).at(0) != '~')) || (lastSymbol->isFunction() && !overview.prettyName(name).contains("::~"))) )
            {
                //qDebug() << arglist;
                QRegExp rx("void *");
                rx.setPatternSyntax(QRegExp::Wildcard);
                if(!rx.exactMatch(arglist))
                {
                    // dirty workarround
                    int last;
                    if(arglist.contains('>'))
                        last = arglist.lastIndexOf('>') + 1;
                    else
                        last = arglist.lastIndexOf(' ');

                    arglist.chop(arglist.size() - last);
                    docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "return " +  arglist + "\n";
                }

            }
            docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
        }
    }

    // Write the documentation in the editor
    if (editorWidget)
    {
        if(printAtEnd)
            editorWidget->moveCursor(QTextCursor::EndOfLine);
        else
            editorWidget->moveCursor(QTextCursor::StartOfBlock);
        editorWidget->insertPlainText(docToWrite);
    }

}

void Doxygen::addSymbol(const CPlusPlus::Symbol* symbol, QMap<unsigned, const CPlusPlus::Symbol*> &symmap)
{
    if(!symbol) return;

    if(symbol->isArgument()
        ||symbol->isFunction()
        || symbol->isDeclaration()
        || symbol->isEnum())
        {
        symmap.insert(symbol->line(), symbol);
        return;
    }
    else if(symbol->isForwardClassDeclaration()
        || symbol->isExtern()
        || symbol->isFriend()
        || symbol->isGenerated()
        || symbol->isUsingNamespaceDirective()
        || symbol->isUsingDeclaration()
        )
        {
        return;
    }
    symmap.insert(symbol->line(), symbol);

    const CPlusPlus::ScopedSymbol *scopedSymbol = symbol->asScopedSymbol();
    if (scopedSymbol)
    {
        CPlusPlus::Scope *scope = scopedSymbol->members();
        if (scope)
        {
            CPlusPlus::Scope::iterator cur = scope->firstSymbol();
            while (cur != scope->lastSymbol())
            {
                const CPlusPlus::Symbol *curSymbol = *cur;
                ++cur;
                if (!curSymbol)
                    continue;
                addSymbol(curSymbol, symmap);
            }
        }
    }

}

void Doxygen::documentFile(const DoxygenSettingsStruct &DoxySettings)
{
    const Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    // before continuing, test if the editor is actually showing a file.
    if(!editor) return;

    CppTools::CppModelManagerInterface *modelManager =
            ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
    if (!modelManager)
        return;
    const Snapshot snapshot = modelManager->snapshot();
    Document::Ptr doc = snapshot.document(editor->file()->fileName());
    if (!doc)
        return;

    Scope *scope = doc->globalSymbols();
    if(!scope)
    {
        return;
    }

    unsigned symbolcount = scope->symbolCount();

    QMap<unsigned, const Symbol*> symmap;
    for(unsigned i = 0; i < symbolcount; ++i)
        addSymbol(scope->symbolAt(i), symmap);

    TextEditor::BaseTextEditor *editorWidget = qobject_cast<TextEditor::BaseTextEditor*>(
            editorManager->currentEditor()->widget());

    if (editorWidget)
    {
        QMap<unsigned, const Symbol*>::iterator it = symmap.end();
        for(; it != symmap.begin(); --it)
        {
            unsigned line = (it-1).key();
            editorWidget->gotoLine(line);
            createDocumentation(DoxySettings);
        }
    }
}

<commit_msg>fixed a bug I introduced stupidly... damn parenthesis, looks like LISP code.<commit_after>/**************************************************************************
**
** This file is part of Doxygen plugin for Qt Creator
**
** Copyright (c) 2009 Kevin Tanguy (kofee@kofee.org).
**
** This plugin is free software: you can redistribute it and/or modify
** it under the terms of the GNU Lesser General Public License as
** published by the Free Software Foundation, either version 2.1
** of the License, or (at your option) any later version.
**
** This plugin 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 Lesser General Public License for more details.
**
** You should have received a copy of the GNU General Public License
** along with Doxygen Plugin. If not, see <http://www.gnu.org/licenses/>.
**/

#include "doxygen.h"

#include <QObject>
#include <plugins/cppeditor/cppeditorconstants.h>
#include <plugins/cpptools/cpptoolsconstants.h>
#include <plugins/cpptools/cppmodelmanagerinterface.h>
#include <plugins/texteditor/basetexteditor.h>
#include <plugins/coreplugin/icore.h>
#include <plugins/coreplugin/uniqueidmanager.h>
#include <plugins/coreplugin/mimedatabase.h>
#include <plugins/coreplugin/actionmanager/actionmanager.h>
#include <plugins/coreplugin/editormanager/ieditor.h>
#include <plugins/coreplugin/editormanager/editormanager.h>
#include <plugins/projectexplorer/project.h>
#include <plugins/projectexplorer/projectexplorer.h>
#include <plugins/projectexplorer/session.h>
#include <plugins/projectexplorer/projectexplorerconstants.h>

#include <libs/cplusplus/Overview.h>
#include <libs/extensionsystem/pluginmanager.h>
#include <shared/cplusplus/Scope.h>
#include <shared/cplusplus/Symbols.h>
#include <shared/cplusplus/Names.h>
#include <cplusplus/CppDocument.h>
#include <cplusplus/CppBindings.h>

#include <QString>
#include <QStringList>
#include <QFile>
#include <QFileInfo>
#include <QDebug>
#include <QRegExp>

using namespace CPlusPlus;
using namespace ProjectExplorer;
using namespace DoxyPlugin;
using namespace DoxyPlugin::Internal;

Doxygen* Doxygen::m_instance = 0;

Doxygen::Doxygen()
{
}

Doxygen* Doxygen::instance()
{
    if (!m_instance)
        m_instance = new Doxygen();
    return m_instance;
}

// TODO, get rid of it.
QStringList scopesForSymbol(const Symbol* symbol)
{
    Scope *scope = symbol->scope();
    QStringList scopes;

    if(symbol->isFunction())
    {
        const Name *name = symbol->name();
        Overview overview;
        overview.setShowArgumentNames(false);
        overview.setShowReturnTypes(false);
        scopes.prepend(overview.prettyName(name));
        return scopes;
    }

    for (; scope; scope = scope->enclosingScope())
    {
        Symbol *owner = scope->owner();

        if (owner && owner->name() && ! scope->isEnumScope())
        {
            const Name *name = owner->name();
            Overview overview;
            overview.setShowArgumentNames(false);
            overview.setShowReturnTypes(false);
            scopes.prepend(overview.prettyName(name));
        }
    }
    return scopes;
}

Symbol* currentSymbol(Core::IEditor *editor)
{
    int line = editor->currentLine();
    int column = editor->currentColumn();

    CppTools::CppModelManagerInterface *modelManager =
            ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
    if (!modelManager)
        return 0;
    const Snapshot snapshot = modelManager->snapshot();
    Document::Ptr doc = snapshot.document(editor->file()->fileName());
    if (!doc)
        return 0;
    return doc->findSymbolAt(line, column);
}

// TODO, recode it entirely.
void Doxygen::createDocumentation(const DoxygenSettingsStruct &DoxySettings)
{
    const Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    // before continuing, test if the editor is actually showing a file.
    if(!editor) return;

    // get the widget for later.
    TextEditor::BaseTextEditor *editorWidget = qobject_cast<TextEditor::BaseTextEditor*>(
            editorManager->currentEditor()->widget());

    // TODO, only do that if class and verbosePrinting
    // Catch hold of the plugin-manager
    ExtensionSystem::PluginManager* pm
            = ExtensionSystem::PluginManager::instance();
    // Look for the ProjectExplorerPlugin object
    ProjectExplorer::ProjectExplorerPlugin* projectExplorerPlugin
            = pm->getObject<ProjectExplorer::ProjectExplorerPlugin>();
    // Fetch a list of all open projects
    QList<ProjectExplorer::Project*> projects
            = projectExplorerPlugin->session()->projects();
    // Project root directory
    QString projectRoot;

    // Attempt to find our project
    Q_FOREACH(ProjectExplorer::Project* project, projects)
    {
        QStringList files = project->files(Project::ExcludeGeneratedFiles); // ProjectExplorer::Project::FilesMode::ExcludeGeneratedFiles
        // is it our project ?
        if(files.contains(editor->file()->fileName()))
        {
            // YES! get the .pro and remove the directory part from our filename
            // TODO, check if it is smart... (it's not really.)
            Q_FOREACH(QString f, files)
            {
                if(f.contains(QRegExp(".pro$")))
                {
                    projectRoot = f.section('/', 0, -2);
                    if(projectRoot.size()) projectRoot.append("/");
                    continue;
                }
            }
            if(projectRoot.size()) continue;
        }
    }

    Symbol *lastSymbol = currentSymbol(editor);
    if (!lastSymbol || !lastSymbol->scope())
        return;

    QStringList scopes = scopesForSymbol(lastSymbol);
    Overview overview;
    overview.setShowArgumentNames(true);
    overview.setShowReturnTypes(true);
    overview.setShowFullyQualifiedNamed(true);
    overview.setShowFunctionSignatures(true);
    const Name *name = lastSymbol->name();
    scopes.append(overview.prettyName(name));

    QString docToWrite;

    // Do we print a short documentation block at end of line?
    bool printAtEnd = false;

    // Get current indentation as per bug #5
    QString indent;
    editorWidget->moveCursor(QTextCursor::StartOfLine);
    editorWidget->gotoLineEndWithSelection();
    QString currentText = editorWidget->textCursor().selectedText();
    QStringList textList = currentText.split(QRegExp("\\b"));
    indent = textList.at(0);
    if(indent.endsWith('~'))
    {
        indent.chop(1);
    }

    if(lastSymbol->isClass())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }
        if(DoxySettings.verbosePrinting)
        {
            QString fileName = editor->file()->fileName().remove(0, editor->file()->fileName().lastIndexOf("/") + 1);
            QString fileNameProj = editor->file()->fileName().remove(projectRoot);
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "class " + overview.prettyName(name) + " " + fileName + " \"" + fileNameProj + "\"\n";
        }
        docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
    }
    else if(lastSymbol->isTypedef())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }
        if(DoxySettings.verbosePrinting)
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "typedef " + overview.prettyName(name);
        docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
    }
    else if(lastSymbol->isEnum())
    {
        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
        docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        if(DoxySettings.verbosePrinting)
            docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "enum " + overview.prettyName(name) + "\n";
        docToWrite += DoxySettings.DoxyComment.doxEnding;
    }
    // Here comes the bitch.
    else if(lastSymbol->isDeclaration() || lastSymbol->isFunction())
    {
        overview.setShowArgumentNames(true);
        overview.setShowReturnTypes(false);
        overview.setShowFullyQualifiedNamed(true);
        overview.setShowFunctionSignatures(true);
        QString arglist = overview.prettyType(lastSymbol->type(), name);

        docToWrite += indent + DoxySettings.DoxyComment.doxBegin;
        if(DoxySettings.printBrief)
        {
            docToWrite += indent + DoxySettings.DoxyComment.doxBrief;
            docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine;
        }

        // if variable, do it quickly...
        if(!arglist.contains('('))
        {
            if(DoxySettings.shortVarDoc)
            {
                printAtEnd = true;
                docToWrite = DoxySettings.DoxyComment.doxShortVarDoc + "TODO */";
            }
            else
            {
                if(DoxySettings.verbosePrinting)
                    docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "var " + overview.prettyName(name) + "\n" + indent + DoxySettings.DoxyComment.doxEnding;
                else
                    docToWrite += indent + DoxySettings.DoxyComment.doxEmptyLine + indent + DoxySettings.DoxyComment.doxEnding;
            }
        }
        else
        {
            // Never noticed it before, a useless comment block because of the Q_OBJECT macro
            // so let's just ignore that will we?
            if(overview.prettyName(name) == "qt_metacall")
                return;

            if(DoxySettings.verbosePrinting)
                docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "fn " + overview.prettyName(name) + "\n";

            // Check parameters
            // Do it the naive way first before finding better in the API
            qDebug() << arglist;
            arglist.remove(0, arglist.indexOf("(") + 1);
            arglist.remove(arglist.lastIndexOf(")"), arglist.size() - arglist.lastIndexOf(")"));
            int indexfrom, indexto;
            while( ((indexfrom = arglist.indexOf('<'))!= -1) && ((indexto = arglist.indexOf('>')) != -1) )
            {
                arglist.remove(indexfrom, indexto - indexfrom + 1);
            }
            QStringList args = arglist.trimmed().split(',', QString::SkipEmptyParts);

            Q_FOREACH(QString singleArg, args)
            {
                singleArg.remove(QRegExp("\\s*=.*")); // FIXME probably don't need the * after \\s but...
                singleArg.replace("*","");
                singleArg.replace("&","");
                docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "param " + singleArg.section(' ',  -1) + "\n";
            }

            // And now check the return type
            overview.setShowArgumentNames(false);
            overview.setShowReturnTypes(true);
            overview.setShowFullyQualifiedNamed(false);
            overview.setShowFunctionSignatures(false);

            arglist = overview.prettyType(lastSymbol->type(), name);

            // FIXME this check is just insane...
            if( arglist.contains(' ') && (((overview.prettyName(name) != scopes.front()) && (overview.prettyName(name).at(0) != '~')) || (lastSymbol->isFunction() && !overview.prettyName(name).contains("::~"))) )
            {
                //qDebug() << arglist;
                QRegExp rx("void *");
                rx.setPatternSyntax(QRegExp::Wildcard);
                if(!rx.exactMatch(arglist))
                {
                    // dirty workarround
                    int last;
                    if(arglist.contains('>'))
                        last = arglist.lastIndexOf('>') + 1;
                    else
                        last = arglist.lastIndexOf(' ');

                    arglist.chop(arglist.size() - last);
                    docToWrite += indent + DoxySettings.DoxyComment.doxNewLine + "return " +  arglist + "\n";
                }

            }
            docToWrite += indent + DoxySettings.DoxyComment.doxEnding;
        }
    }

    // Write the documentation in the editor
    if (editorWidget)
    {
        if(printAtEnd)
            editorWidget->moveCursor(QTextCursor::EndOfLine);
        else
            editorWidget->moveCursor(QTextCursor::StartOfBlock);
        editorWidget->insertPlainText(docToWrite);
    }

}

void Doxygen::addSymbol(const CPlusPlus::Symbol* symbol, QMap<unsigned, const CPlusPlus::Symbol*> &symmap)
{
    if(!symbol) return;

    if(symbol->isArgument()
        ||symbol->isFunction()
        || symbol->isDeclaration()
        || symbol->isEnum())
        {
        symmap.insert(symbol->line(), symbol);
        return;
    }
    else if(symbol->isForwardClassDeclaration()
        || symbol->isExtern()
        || symbol->isFriend()
        || symbol->isGenerated()
        || symbol->isUsingNamespaceDirective()
        || symbol->isUsingDeclaration()
        )
        {
        return;
    }
    symmap.insert(symbol->line(), symbol);

    const CPlusPlus::ScopedSymbol *scopedSymbol = symbol->asScopedSymbol();
    if (scopedSymbol)
    {
        CPlusPlus::Scope *scope = scopedSymbol->members();
        if (scope)
        {
            CPlusPlus::Scope::iterator cur = scope->firstSymbol();
            while (cur != scope->lastSymbol())
            {
                const CPlusPlus::Symbol *curSymbol = *cur;
                ++cur;
                if (!curSymbol)
                    continue;
                addSymbol(curSymbol, symmap);
            }
        }
    }

}

void Doxygen::documentFile(const DoxygenSettingsStruct &DoxySettings)
{
    const Core::EditorManager *editorManager = Core::EditorManager::instance();
    Core::IEditor *editor = editorManager->currentEditor();

    // before continuing, test if the editor is actually showing a file.
    if(!editor)
        return;

    CppTools::CppModelManagerInterface *modelManager =
            ExtensionSystem::PluginManager::instance()->getObject<CppTools::CppModelManagerInterface>();
    if(!modelManager)
        return;

    const Snapshot snapshot = modelManager->snapshot();
    Document::Ptr doc = snapshot.document(editor->file()->fileName());
    if (!doc)
        return;

    Scope *scope = doc->globalSymbols();
    if(!scope)
        return;

    unsigned symbolcount = scope->symbolCount();

    QMap<unsigned, const Symbol*> symmap;
    for(unsigned i = 0; i < symbolcount; ++i)
        addSymbol(scope->symbolAt(i), symmap);

    TextEditor::BaseTextEditor *editorWidget = qobject_cast<TextEditor::BaseTextEditor*>(
            editorManager->currentEditor()->widget());

    if (editorWidget)
    {
        QMap<unsigned, const Symbol*>::iterator it = symmap.end();
        for(; it != symmap.begin(); --it)
        {
            unsigned line = (it-1).key();
            editorWidget->gotoLine(line);
            createDocumentation(DoxySettings);
        }
    }
}

<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h"

#include <string>
#include <utility>

#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync_file_system/sync_file_status.h"
#include "chrome/browser/sync_file_system/sync_file_system_service.h"
#include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
#include "chrome/common/extensions/api/sync_file_system.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_client.h"
#include "storage/browser/fileapi/file_system_context.h"
#include "storage/browser/fileapi/file_system_url.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/common/fileapi/file_system_types.h"
#include "storage/common/fileapi/file_system_util.h"

using content::BrowserContext;
using content::BrowserThread;
using sync_file_system::ConflictResolutionPolicy;
using sync_file_system::SyncFileStatus;
using sync_file_system::SyncFileSystemServiceFactory;
using sync_file_system::SyncStatusCode;

namespace extensions {

namespace {

// Error messages.
const char kErrorMessage[] = "%s (error code: %d).";
const char kUnsupportedConflictResolutionPolicy[] =
    "Policy %s is not supported.";

sync_file_system::SyncFileSystemService* GetSyncFileSystemService(
    Profile* profile) {
  sync_file_system::SyncFileSystemService* service =
      SyncFileSystemServiceFactory::GetForProfile(profile);
  DCHECK(service);
  ExtensionSyncEventObserver* observer =
      ExtensionSyncEventObserver::GetFactoryInstance()->Get(profile);
  DCHECK(observer);
  observer->InitializeForService(service);
  return service;
}

std::string ErrorToString(SyncStatusCode code) {
  return base::StringPrintf(
      kErrorMessage,
      sync_file_system::SyncStatusCodeToString(code),
      static_cast<int>(code));
}

}  // namespace

bool SyncFileSystemDeleteFileSystemFunction::RunAsync() {
  std::string url;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));

  scoped_refptr<storage::FileSystemContext> file_system_context =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetFileSystemContext();
  storage::FileSystemURL file_system_url(
      file_system_context->CrackURL(GURL(url)));

  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      Bind(&storage::FileSystemContext::DeleteFileSystem,
           file_system_context,
           source_url().GetOrigin(),
           file_system_url.type(),
           Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem,
                this)));
  return true;
}

void SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem(
    base::File::Error error) {
  // Repost to switch from IO thread to UI thread for SendResponse().
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, this,
             error));
    return;
  }

  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (error != base::File::FILE_OK) {
    error_ = ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error));
    SetResult(new base::FundamentalValue(false));
    SendResponse(false);
    return;
  }

  SetResult(new base::FundamentalValue(true));
  SendResponse(true);
}

bool SyncFileSystemRequestFileSystemFunction::RunAsync() {
  // SyncFileSystem initialization is done in OpenFileSystem below, but we call
  // GetSyncFileSystemService here too to initialize sync event observer for
  // extensions API.
  GetSyncFileSystemService(GetProfile());

  // Initializes sync context for this extension and continue to open
  // a new file system.
  BrowserThread::PostTask(BrowserThread::IO,
                          FROM_HERE,
                          Bind(&storage::FileSystemContext::OpenFileSystem,
                               GetFileSystemContext(),
                               source_url().GetOrigin(),
                               storage::kFileSystemTypeSyncable,
                               storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
                               base::Bind(&self::DidOpenFileSystem, this)));
  return true;
}

storage::FileSystemContext*
SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() {
  DCHECK(render_view_host());
  return BrowserContext::GetStoragePartition(
      GetProfile(), render_view_host()->GetSiteInstance())
      ->GetFileSystemContext();
}

void SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem(
    const GURL& root_url,
    const std::string& file_system_name,
    base::File::Error error) {
  // Repost to switch from IO thread to UI thread for SendResponse().
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        Bind(&SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem,
             this, root_url, file_system_name, error));
    return;
  }

  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (error != base::File::FILE_OK) {
    error_ = ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error));
    SendResponse(false);
    return;
  }

  base::DictionaryValue* dict = new base::DictionaryValue();
  SetResult(dict);
  dict->SetString("name", file_system_name);
  dict->SetString("root", root_url.spec());
  SendResponse(true);
}

bool SyncFileSystemGetFileStatusFunction::RunAsync() {
  std::string url;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));

  scoped_refptr<storage::FileSystemContext> file_system_context =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetFileSystemContext();
  storage::FileSystemURL file_system_url(
      file_system_context->CrackURL(GURL(url)));

  GetSyncFileSystemService(GetProfile())->GetFileSyncStatus(
      file_system_url,
      Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus, this));
  return true;
}

void SyncFileSystemGetFileStatusFunction::DidGetFileStatus(
    const SyncStatusCode sync_status_code,
    const SyncFileStatus sync_file_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (sync_status_code != sync_file_system::SYNC_STATUS_OK) {
    error_ = ErrorToString(sync_status_code);
    SendResponse(false);
    return;
  }

  // Convert from C++ to JavaScript enum.
  results_ = api::sync_file_system::GetFileStatus::Results::Create(
      SyncFileStatusToExtensionEnum(sync_file_status));
  SendResponse(true);
}

SyncFileSystemGetFileStatusesFunction::SyncFileSystemGetFileStatusesFunction() {
}

SyncFileSystemGetFileStatusesFunction::~SyncFileSystemGetFileStatusesFunction(
    ) {}

bool SyncFileSystemGetFileStatusesFunction::RunAsync() {
  // All FileEntries converted into array of URL Strings in JS custom bindings.
  base::ListValue* file_entry_urls = NULL;
  EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &file_entry_urls));

  scoped_refptr<storage::FileSystemContext> file_system_context =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetFileSystemContext();

  // Map each file path->SyncFileStatus in the callback map.
  // TODO(calvinlo): Overload GetFileSyncStatus to take in URL array.
  num_expected_results_ = file_entry_urls->GetSize();
  num_results_received_ = 0;
  file_sync_statuses_.clear();
  sync_file_system::SyncFileSystemService* sync_file_system_service =
      GetSyncFileSystemService(GetProfile());
  for (unsigned int i = 0; i < num_expected_results_; i++) {
    std::string url;
    file_entry_urls->GetString(i, &url);
    storage::FileSystemURL file_system_url(
        file_system_context->CrackURL(GURL(url)));

    sync_file_system_service->GetFileSyncStatus(
        file_system_url,
        Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus,
             this, file_system_url));
  }

  return true;
}

void SyncFileSystemGetFileStatusesFunction::DidGetFileStatus(
    const storage::FileSystemURL& file_system_url,
    SyncStatusCode sync_status_code,
    SyncFileStatus sync_file_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  num_results_received_++;
  DCHECK_LE(num_results_received_, num_expected_results_);

  file_sync_statuses_[file_system_url] =
      std::make_pair(sync_status_code, sync_file_status);

  // Keep mapping file statuses until all of them have been received.
  // TODO(calvinlo): Get rid of this check when batch version of
  // GetFileSyncStatus(GURL urls[]); is added.
  if (num_results_received_ < num_expected_results_)
    return;

  // All results received. Dump array of statuses into extension enum values.
  // Note that the enum types need to be set as strings manually as the
  // autogenerated Results::Create function thinks the enum values should be
  // returned as int values.
  base::ListValue* status_array = new base::ListValue();
  for (URLToStatusMap::iterator it = file_sync_statuses_.begin();
       it != file_sync_statuses_.end(); ++it) {
    base::DictionaryValue* dict = new base::DictionaryValue();
    status_array->Append(dict);

    storage::FileSystemURL url = it->first;
    SyncStatusCode file_error = it->second.first;
    api::sync_file_system::FileStatus file_status =
        SyncFileStatusToExtensionEnum(it->second.second);

    dict->Set("entry", CreateDictionaryValueForFileSystemEntry(
        url, sync_file_system::SYNC_FILE_TYPE_FILE));
    dict->SetString("status", ToString(file_status));

    if (file_error == sync_file_system::SYNC_STATUS_OK)
      continue;
    dict->SetString("error", ErrorToString(file_error));
  }
  SetResult(status_array);

  SendResponse(true);
}

bool SyncFileSystemGetUsageAndQuotaFunction::RunAsync() {
  std::string url;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));

  scoped_refptr<storage::FileSystemContext> file_system_context =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetFileSystemContext();
  storage::FileSystemURL file_system_url(
      file_system_context->CrackURL(GURL(url)));

  scoped_refptr<storage::QuotaManager> quota_manager =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetQuotaManager();

  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      Bind(&storage::QuotaManager::GetUsageAndQuotaForWebApps,
           quota_manager,
           source_url().GetOrigin(),
           storage::FileSystemTypeToQuotaStorageType(file_system_url.type()),
           Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota,
                this)));

  return true;
}

void SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota(
    storage::QuotaStatusCode status,
    int64 usage,
    int64 quota) {
  // Repost to switch from IO thread to UI thread for SendResponse().
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, this,
             status, usage, quota));
    return;
  }

  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (status != storage::kQuotaStatusOk) {
    error_ = QuotaStatusCodeToString(status);
    SendResponse(false);
    return;
  }

  api::sync_file_system::StorageInfo info;
  info.usage_bytes = usage;
  info.quota_bytes = quota;
  results_ = api::sync_file_system::GetUsageAndQuota::Results::Create(info);
  SendResponse(true);
}

bool SyncFileSystemSetConflictResolutionPolicyFunction::RunSync() {
  std::string policy_string;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &policy_string));
  ConflictResolutionPolicy policy = ExtensionEnumToConflictResolutionPolicy(
      api::sync_file_system::ParseConflictResolutionPolicy(policy_string));
  if (policy != sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN) {
    SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy,
                                policy_string.c_str()));
    return false;
  }
  return true;
}

bool SyncFileSystemGetConflictResolutionPolicyFunction::RunSync() {
  SetResult(new base::StringValue(
      api::sync_file_system::ToString(
          api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN)));
  return true;
}

bool SyncFileSystemGetServiceStatusFunction::RunSync() {
  sync_file_system::SyncFileSystemService* service =
      GetSyncFileSystemService(GetProfile());
  results_ = api::sync_file_system::GetServiceStatus::Results::Create(
      SyncServiceStateToExtensionEnum(service->GetSyncServiceState()));
  return true;
}

}  // namespace extensions
<commit_msg>Ensure availablility of SyncFileSystemService on JS API call<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api.h"

#include <string>
#include <utility>

#include "base/bind.h"
#include "base/logging.h"
#include "base/strings/stringprintf.h"
#include "chrome/browser/extensions/api/sync_file_system/extension_sync_event_observer.h"
#include "chrome/browser/extensions/api/sync_file_system/sync_file_system_api_helpers.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/sync_file_system/sync_file_status.h"
#include "chrome/browser/sync_file_system/sync_file_system_service.h"
#include "chrome/browser/sync_file_system/sync_file_system_service_factory.h"
#include "chrome/common/extensions/api/sync_file_system.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/storage_partition.h"
#include "content/public/common/content_client.h"
#include "storage/browser/fileapi/file_system_context.h"
#include "storage/browser/fileapi/file_system_url.h"
#include "storage/browser/quota/quota_manager.h"
#include "storage/common/fileapi/file_system_types.h"
#include "storage/common/fileapi/file_system_util.h"

using content::BrowserContext;
using content::BrowserThread;
using sync_file_system::ConflictResolutionPolicy;
using sync_file_system::SyncFileStatus;
using sync_file_system::SyncFileSystemServiceFactory;
using sync_file_system::SyncStatusCode;

namespace extensions {

namespace {

// Error messages.
const char kErrorMessage[] = "%s (error code: %d).";
const char kUnsupportedConflictResolutionPolicy[] =
    "Policy %s is not supported.";

sync_file_system::SyncFileSystemService* GetSyncFileSystemService(
    Profile* profile) {
  sync_file_system::SyncFileSystemService* service =
      SyncFileSystemServiceFactory::GetForProfile(profile);
  if (!service)
    return nullptr;
  ExtensionSyncEventObserver* observer =
      ExtensionSyncEventObserver::GetFactoryInstance()->Get(profile);
  if (!observer)
    return nullptr;
  observer->InitializeForService(service);
  return service;
}

std::string ErrorToString(SyncStatusCode code) {
  return base::StringPrintf(
      kErrorMessage,
      sync_file_system::SyncStatusCodeToString(code),
      static_cast<int>(code));
}

}  // namespace

bool SyncFileSystemDeleteFileSystemFunction::RunAsync() {
  std::string url;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));

  scoped_refptr<storage::FileSystemContext> file_system_context =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetFileSystemContext();
  storage::FileSystemURL file_system_url(
      file_system_context->CrackURL(GURL(url)));

  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      Bind(&storage::FileSystemContext::DeleteFileSystem,
           file_system_context,
           source_url().GetOrigin(),
           file_system_url.type(),
           Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem,
                this)));
  return true;
}

void SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem(
    base::File::Error error) {
  // Repost to switch from IO thread to UI thread for SendResponse().
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        Bind(&SyncFileSystemDeleteFileSystemFunction::DidDeleteFileSystem, this,
             error));
    return;
  }

  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (error != base::File::FILE_OK) {
    error_ = ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error));
    SetResult(new base::FundamentalValue(false));
    SendResponse(false);
    return;
  }

  SetResult(new base::FundamentalValue(true));
  SendResponse(true);
}

bool SyncFileSystemRequestFileSystemFunction::RunAsync() {
  // SyncFileSystem initialization is done in OpenFileSystem below, but we call
  // GetSyncFileSystemService here too to initialize sync event observer for
  // extensions API.
  if (!GetSyncFileSystemService(GetProfile()))
    return false;

  // Initializes sync context for this extension and continue to open
  // a new file system.
  BrowserThread::PostTask(BrowserThread::IO,
                          FROM_HERE,
                          Bind(&storage::FileSystemContext::OpenFileSystem,
                               GetFileSystemContext(),
                               source_url().GetOrigin(),
                               storage::kFileSystemTypeSyncable,
                               storage::OPEN_FILE_SYSTEM_CREATE_IF_NONEXISTENT,
                               base::Bind(&self::DidOpenFileSystem, this)));
  return true;
}

storage::FileSystemContext*
SyncFileSystemRequestFileSystemFunction::GetFileSystemContext() {
  DCHECK(render_view_host());
  return BrowserContext::GetStoragePartition(
      GetProfile(), render_view_host()->GetSiteInstance())
      ->GetFileSystemContext();
}

void SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem(
    const GURL& root_url,
    const std::string& file_system_name,
    base::File::Error error) {
  // Repost to switch from IO thread to UI thread for SendResponse().
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        Bind(&SyncFileSystemRequestFileSystemFunction::DidOpenFileSystem,
             this, root_url, file_system_name, error));
    return;
  }

  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (error != base::File::FILE_OK) {
    error_ = ErrorToString(sync_file_system::FileErrorToSyncStatusCode(error));
    SendResponse(false);
    return;
  }

  base::DictionaryValue* dict = new base::DictionaryValue();
  SetResult(dict);
  dict->SetString("name", file_system_name);
  dict->SetString("root", root_url.spec());
  SendResponse(true);
}

bool SyncFileSystemGetFileStatusFunction::RunAsync() {
  std::string url;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));

  scoped_refptr<storage::FileSystemContext> file_system_context =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetFileSystemContext();
  storage::FileSystemURL file_system_url(
      file_system_context->CrackURL(GURL(url)));

  sync_file_system::SyncFileSystemService* sync_file_system_service =
      GetSyncFileSystemService(GetProfile());
  if (!sync_file_system_service)
    return false;

  sync_file_system_service->GetFileSyncStatus(
      file_system_url,
      Bind(&SyncFileSystemGetFileStatusFunction::DidGetFileStatus, this));
  return true;
}

void SyncFileSystemGetFileStatusFunction::DidGetFileStatus(
    const SyncStatusCode sync_status_code,
    const SyncFileStatus sync_file_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (sync_status_code != sync_file_system::SYNC_STATUS_OK) {
    error_ = ErrorToString(sync_status_code);
    SendResponse(false);
    return;
  }

  // Convert from C++ to JavaScript enum.
  results_ = api::sync_file_system::GetFileStatus::Results::Create(
      SyncFileStatusToExtensionEnum(sync_file_status));
  SendResponse(true);
}

SyncFileSystemGetFileStatusesFunction::SyncFileSystemGetFileStatusesFunction() {
}

SyncFileSystemGetFileStatusesFunction::~SyncFileSystemGetFileStatusesFunction(
    ) {}

bool SyncFileSystemGetFileStatusesFunction::RunAsync() {
  // All FileEntries converted into array of URL Strings in JS custom bindings.
  base::ListValue* file_entry_urls = NULL;
  EXTENSION_FUNCTION_VALIDATE(args_->GetList(0, &file_entry_urls));

  scoped_refptr<storage::FileSystemContext> file_system_context =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetFileSystemContext();

  // Map each file path->SyncFileStatus in the callback map.
  // TODO(calvinlo): Overload GetFileSyncStatus to take in URL array.
  num_expected_results_ = file_entry_urls->GetSize();
  num_results_received_ = 0;
  file_sync_statuses_.clear();
  sync_file_system::SyncFileSystemService* sync_file_system_service =
      GetSyncFileSystemService(GetProfile());
  if (!sync_file_system_service)
    return false;

  for (unsigned int i = 0; i < num_expected_results_; i++) {
    std::string url;
    file_entry_urls->GetString(i, &url);
    storage::FileSystemURL file_system_url(
        file_system_context->CrackURL(GURL(url)));

    sync_file_system_service->GetFileSyncStatus(
        file_system_url,
        Bind(&SyncFileSystemGetFileStatusesFunction::DidGetFileStatus,
             this, file_system_url));
  }

  return true;
}

void SyncFileSystemGetFileStatusesFunction::DidGetFileStatus(
    const storage::FileSystemURL& file_system_url,
    SyncStatusCode sync_status_code,
    SyncFileStatus sync_file_status) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  num_results_received_++;
  DCHECK_LE(num_results_received_, num_expected_results_);

  file_sync_statuses_[file_system_url] =
      std::make_pair(sync_status_code, sync_file_status);

  // Keep mapping file statuses until all of them have been received.
  // TODO(calvinlo): Get rid of this check when batch version of
  // GetFileSyncStatus(GURL urls[]); is added.
  if (num_results_received_ < num_expected_results_)
    return;

  // All results received. Dump array of statuses into extension enum values.
  // Note that the enum types need to be set as strings manually as the
  // autogenerated Results::Create function thinks the enum values should be
  // returned as int values.
  base::ListValue* status_array = new base::ListValue();
  for (URLToStatusMap::iterator it = file_sync_statuses_.begin();
       it != file_sync_statuses_.end(); ++it) {
    base::DictionaryValue* dict = new base::DictionaryValue();
    status_array->Append(dict);

    storage::FileSystemURL url = it->first;
    SyncStatusCode file_error = it->second.first;
    api::sync_file_system::FileStatus file_status =
        SyncFileStatusToExtensionEnum(it->second.second);

    dict->Set("entry", CreateDictionaryValueForFileSystemEntry(
        url, sync_file_system::SYNC_FILE_TYPE_FILE));
    dict->SetString("status", ToString(file_status));

    if (file_error == sync_file_system::SYNC_STATUS_OK)
      continue;
    dict->SetString("error", ErrorToString(file_error));
  }
  SetResult(status_array);

  SendResponse(true);
}

bool SyncFileSystemGetUsageAndQuotaFunction::RunAsync() {
  std::string url;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &url));

  scoped_refptr<storage::FileSystemContext> file_system_context =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetFileSystemContext();
  storage::FileSystemURL file_system_url(
      file_system_context->CrackURL(GURL(url)));

  scoped_refptr<storage::QuotaManager> quota_manager =
      BrowserContext::GetStoragePartition(GetProfile(),
                                          render_view_host()->GetSiteInstance())
          ->GetQuotaManager();

  BrowserThread::PostTask(
      BrowserThread::IO,
      FROM_HERE,
      Bind(&storage::QuotaManager::GetUsageAndQuotaForWebApps,
           quota_manager,
           source_url().GetOrigin(),
           storage::FileSystemTypeToQuotaStorageType(file_system_url.type()),
           Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota,
                this)));

  return true;
}

void SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota(
    storage::QuotaStatusCode status,
    int64 usage,
    int64 quota) {
  // Repost to switch from IO thread to UI thread for SendResponse().
  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    BrowserThread::PostTask(
        BrowserThread::UI,
        FROM_HERE,
        Bind(&SyncFileSystemGetUsageAndQuotaFunction::DidGetUsageAndQuota, this,
             status, usage, quota));
    return;
  }

  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (status != storage::kQuotaStatusOk) {
    error_ = QuotaStatusCodeToString(status);
    SendResponse(false);
    return;
  }

  api::sync_file_system::StorageInfo info;
  info.usage_bytes = usage;
  info.quota_bytes = quota;
  results_ = api::sync_file_system::GetUsageAndQuota::Results::Create(info);
  SendResponse(true);
}

bool SyncFileSystemSetConflictResolutionPolicyFunction::RunSync() {
  std::string policy_string;
  EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &policy_string));
  ConflictResolutionPolicy policy = ExtensionEnumToConflictResolutionPolicy(
      api::sync_file_system::ParseConflictResolutionPolicy(policy_string));
  if (policy != sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN) {
    SetError(base::StringPrintf(kUnsupportedConflictResolutionPolicy,
                                policy_string.c_str()));
    return false;
  }
  return true;
}

bool SyncFileSystemGetConflictResolutionPolicyFunction::RunSync() {
  SetResult(new base::StringValue(
      api::sync_file_system::ToString(
          api::sync_file_system::CONFLICT_RESOLUTION_POLICY_LAST_WRITE_WIN)));
  return true;
}

bool SyncFileSystemGetServiceStatusFunction::RunSync() {
  sync_file_system::SyncFileSystemService* service =
      GetSyncFileSystemService(GetProfile());
  if (!service)
    return false;
  results_ = api::sync_file_system::GetServiceStatus::Results::Create(
      SyncServiceStateToExtensionEnum(service->GetSyncServiceState()));
  return true;
}

}  // namespace extensions
<|endoftext|>


<commit_before>// FRAGMENT(includes)
#include <iostream>

#include <seqan/sequence.h>
#include <seqan/file.h>
#include <seqan/stream.h>

using namespace seqan;

// FRAGMENT(tags)
struct BlastnTab_;
typedef Tag<BlastnTab_> BlastnTab;

struct BlastnTabComment_;
typedef Tag<BlastnTabComment_> BlastnTabComment;

struct BlastnTabAlignment_;
typedef Tag<BlastnTabAlignment_> BlastnTabAlignment;

// FRAGMENT(record)
struct BlastnTabAlignmentRecord
{
    CharString queryName;
    CharString subjectName;
    double identity;
    unsigned alignmentLength;
    unsigned mismatches;
    unsigned gapOpens;
    unsigned queryBegin;
    unsigned queryEnd;
    unsigned subjectBegin;
    unsigned subjectEnd;
    double eValue;
    double bitScore;

    BlastnTabAlignmentRecord() :
            identity(0), alignmentLength(0), mismatches(0), gapOpens(0),
            queryBegin(0), queryEnd(0), subjectBegin(0), subjectEnd(0),
            eValue(0), bitScore(0)
    {}
};

template <typename TStream>
int write(TStream & stream, BlastnTabAlignmentRecord & record)
{
    streamPut(stream, "query name: ");
    streamPut(stream, record.queryName);
    streamPut(stream, "\nsubject name: ");
    streamPut(stream, record.subjectName);
    streamPut(stream, "\nidentity: ");
    streamPut(stream, record.identity);
    streamPut(stream, "\nalignment length: ");
    streamPut(stream, record.alignmentLength);
    streamPut(stream, "\nmismatches: ");
    streamPut(stream, record.mismatches);
    streamPut(stream, "\ngap opens: ");
    streamPut(stream, record.gapOpens);
    streamPut(stream, "\nquery begin: ");
    streamPut(stream, record.queryBegin);
    streamPut(stream, "\nquery end: ");
    streamPut(stream, record.queryEnd);
    streamPut(stream, "\nsubject begin: ");
    streamPut(stream, record.subjectBegin);
    streamPut(stream, "\nsubject end: ");
    streamPut(stream, record.subjectEnd);
    streamPut(stream, "\nevalue: ");
    streamPut(stream, record.eValue);
    streamPut(stream, "\nbit score: ");
    streamPut(stream, record.bitScore);
    int res = streamPut(stream, "\n\n");
    return res;
}

void clear(BlastnTabAlignmentRecord & record)
{
    clear(record.queryName);
    clear(record.subjectName);
}

// FRAGMENT(next-is)
template <typename TStream, typename TSpec>
inline bool
nextIs(RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTabComment const & /*tag*/)
{
    return !atEnd(reader) && value(reader) == '#';
}

template <typename TStream, typename TSpec>
inline bool
nextIs(RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTabAlignment const & /*tag*/)
{
    return !atEnd(reader) && value(reader) != '#';
}

// FRAGMENT(read-record)
template <typename TCharSequence, typename TStream, typename TSpec>
inline int
readRecord(TCharSequence & buffer, RecordReader<TStream, SinglePass<TSpec> > const & reader, BlastnTabComment const & /*tag*/)
{
    SEQAN_ASSERT(nextIs(reader, BlastnTabComment()));
    clear(buffer);
    return readLine(buffer, reader);
}

// FRAGMENT(record)
template <typename TStream, typename TSpec>
inline bool
readRecord(BlastnTabAlignmentRecord & record, RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTabAlignment const & /*tag*/)
{
    SEQAN_ASSERT(nextIs(reader, BlastnTabAlignment()));
    int res = 0;
    CharString buffer;
    clear(record);

    // Read query name.
    res = readUntilChar(record.queryName, reader, '\t');
    if (res != 0)
        return res;
    goNext(reader);

    // Read subject name.
    res = readUntilChar(record.subjectName, reader, '\t');
    if (res != 0)
        return res;
    goNext(reader);

    // Read identity.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<double>(record.identity, buffer))
        return 1;  // Could not cast identity to double.
    goNext(reader);

    // Read alignment length.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.alignmentLength, buffer))
        return 1;  // Could not cast alignment length to unsigned.
    goNext(reader);

    // Read mismatches.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.mismatches, buffer))
        return 1;  // Could not cast mismatches to unsigned.
    goNext(reader);

    // Read gap opens.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.gapOpens, buffer))
        return 1;  // Could not cast gap opens to unsigned.
    goNext(reader);

    // Read query begin.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.queryBegin, buffer))
        return 1;  // Could not cast query begin to unsigned.
    goNext(reader);

    // Read query end.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.queryEnd, buffer))
        return 1;  // Could not cast query end to unsigned.
    goNext(reader);

    // Read subject begin.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.subjectBegin, buffer))
        return 1;  // Could not cast subject begin to unsigned.
    goNext(reader);

    // Read subject end.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.subjectEnd, buffer))
        return 1;  // Could not cast subject end to unsigned.
    goNext(reader);

    // Read evalue.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<double>(record.eValue, buffer))
        return 1;  // Could not cast evalue to double.
    goNext(reader);

    // Read bit score, up to end of the line.
    clear(buffer);
    res = readLine(buffer, reader);
    if (res != 0)
        return res;
    if (!lexicalCast2<double>(record.bitScore, buffer))
        return 1;  // Could not cast bit score to double.

    return 0;
}

// FRAGMENT(skip-record)
template <typename TStream, typename TSpec>
inline int
skipRecord(RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTabComment const & /*tag*/)
{
    return skipLine(reader);
}

template <typename TStream, typename TPass>
inline int
skipRecord(RecordReader<TStream, TPass> & reader, BlastnTabAlignment const & /*tag*/)
{
    return skipLine(reader);
}

// FRAGMENT(batch-read)
template <typename TBlastnTabRecords, typename TStream, typename TSpec>
int read(TBlastnTabRecords & records, RecordReader<TStream, SinglePass<TSpec> > & reader)
{
    BlastnTabAlignmentRecord record;
    while (!atEnd(reader))
    {
        if (nextIs(reader, BlastnTabComment()))
        {
            skipRecord(reader, BlastnTabComment());
            continue;
        }
        if (!nextIs(reader, BlastnTabAlignment()))
            return 1;
        if (readRecord(record, reader, BlastnTabAlignment()) != 0)
            return 1;
        appendValue(records, record);
    }
    return 0;
}

// FRAGMENT(main)
int main(int argc, char const ** argv)
{
    // Process command line arguments, open file.
    if (argc != 2)
    {
        std::cerr << "Incorrect argument count!" << std::endl;
        std::cerr << "USAGE: tutorial_parse_blastn INPUT.txt" << std::endl;
        return 1;
    }
    std::fstream stream(argv[1], std::ios::binary | std::ios::in);
    if (!stream.good())
    {
        std::cerr << "Could not open file " << argv[1] << std::endl;
        return 1;
    }

    // Read file.
    RecordReader<std::fstream, SinglePass<> > reader(stream);
    String<BlastnTabAlignmentRecord> records;
    int res = read(records, reader);
    if (res != 0)
    {
        std::cerr << "Could not read BLASTN records." << std::endl;
        return 1;
    }

    // Write read records.
    for (unsigned i = 0; i < length(records); ++i)
        write(std::cout, records[i]);

    return 0;
}
<commit_msg>Fixing fragments in parse_blastn.cpp demo.<commit_after>// FRAGMENT(includes)
#include <iostream>

#include <seqan/sequence.h>
#include <seqan/file.h>
#include <seqan/stream.h>

using namespace seqan;

// FRAGMENT(tags)
struct BlastnTab_;
typedef Tag<BlastnTab_> BlastnTab;

struct BlastnTabComment_;
typedef Tag<BlastnTabComment_> BlastnTabComment;

struct BlastnTabAlignment_;
typedef Tag<BlastnTabAlignment_> BlastnTabAlignment;

// FRAGMENT(record)
struct BlastnTabAlignmentRecord
{
    CharString queryName;
    CharString subjectName;
    double identity;
    unsigned alignmentLength;
    unsigned mismatches;
    unsigned gapOpens;
    unsigned queryBegin;
    unsigned queryEnd;
    unsigned subjectBegin;
    unsigned subjectEnd;
    double eValue;
    double bitScore;

    BlastnTabAlignmentRecord() :
            identity(0), alignmentLength(0), mismatches(0), gapOpens(0),
            queryBegin(0), queryEnd(0), subjectBegin(0), subjectEnd(0),
            eValue(0), bitScore(0)
    {}
};

template <typename TStream>
int write(TStream & stream, BlastnTabAlignmentRecord & record)
{
    streamPut(stream, "query name: ");
    streamPut(stream, record.queryName);
    streamPut(stream, "\nsubject name: ");
    streamPut(stream, record.subjectName);
    streamPut(stream, "\nidentity: ");
    streamPut(stream, record.identity);
    streamPut(stream, "\nalignment length: ");
    streamPut(stream, record.alignmentLength);
    streamPut(stream, "\nmismatches: ");
    streamPut(stream, record.mismatches);
    streamPut(stream, "\ngap opens: ");
    streamPut(stream, record.gapOpens);
    streamPut(stream, "\nquery begin: ");
    streamPut(stream, record.queryBegin);
    streamPut(stream, "\nquery end: ");
    streamPut(stream, record.queryEnd);
    streamPut(stream, "\nsubject begin: ");
    streamPut(stream, record.subjectBegin);
    streamPut(stream, "\nsubject end: ");
    streamPut(stream, record.subjectEnd);
    streamPut(stream, "\nevalue: ");
    streamPut(stream, record.eValue);
    streamPut(stream, "\nbit score: ");
    streamPut(stream, record.bitScore);
    int res = streamPut(stream, "\n\n");
    return res;
}

void clear(BlastnTabAlignmentRecord & record)
{
    clear(record.queryName);
    clear(record.subjectName);
}

// FRAGMENT(next-is)
template <typename TStream, typename TSpec>
inline bool
nextIs(RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTabComment const & /*tag*/)
{
    return !atEnd(reader) && value(reader) == '#';
}

template <typename TStream, typename TSpec>
inline bool
nextIs(RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTabAlignment const & /*tag*/)
{
    return !atEnd(reader) && value(reader) != '#';
}

// FRAGMENT(read-record)
template <typename TCharSequence, typename TStream, typename TSpec>
inline int
readRecord(TCharSequence & buffer, RecordReader<TStream, SinglePass<TSpec> > const & reader, BlastnTabComment const & /*tag*/)
{
    SEQAN_ASSERT(nextIs(reader, BlastnTabComment()));
    clear(buffer);
    return readLine(buffer, reader);
}

template <typename TStream, typename TSpec>
inline bool
readRecord(BlastnTabAlignmentRecord & record, RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTabAlignment const & /*tag*/)
{
    SEQAN_ASSERT(nextIs(reader, BlastnTabAlignment()));
    int res = 0;
    CharString buffer;
    clear(record);

    // Read query name.
    res = readUntilChar(record.queryName, reader, '\t');
    if (res != 0)
        return res;
    goNext(reader);

    // Read subject name.
    res = readUntilChar(record.subjectName, reader, '\t');
    if (res != 0)
        return res;
    goNext(reader);

    // Read identity.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<double>(record.identity, buffer))
        return 1;  // Could not cast identity to double.
    goNext(reader);

    // Read alignment length.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.alignmentLength, buffer))
        return 1;  // Could not cast alignment length to unsigned.
    goNext(reader);

    // Read mismatches.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.mismatches, buffer))
        return 1;  // Could not cast mismatches to unsigned.
    goNext(reader);

    // Read gap opens.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.gapOpens, buffer))
        return 1;  // Could not cast gap opens to unsigned.
    goNext(reader);

    // Read query begin.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.queryBegin, buffer))
        return 1;  // Could not cast query begin to unsigned.
    goNext(reader);

    // Read query end.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.queryEnd, buffer))
        return 1;  // Could not cast query end to unsigned.
    goNext(reader);

    // Read subject begin.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.subjectBegin, buffer))
        return 1;  // Could not cast subject begin to unsigned.
    goNext(reader);

    // Read subject end.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<unsigned>(record.subjectEnd, buffer))
        return 1;  // Could not cast subject end to unsigned.
    goNext(reader);

    // Read evalue.
    clear(buffer);
    res = readUntilChar(buffer, reader, '\t');
    if (res != 0)
        return res;
    if (!lexicalCast2<double>(record.eValue, buffer))
        return 1;  // Could not cast evalue to double.
    goNext(reader);

    // Read bit score, up to end of the line.
    clear(buffer);
    res = readLine(buffer, reader);
    if (res != 0)
        return res;
    if (!lexicalCast2<double>(record.bitScore, buffer))
        return 1;  // Could not cast bit score to double.

    return 0;
}

// FRAGMENT(skip-record)
template <typename TStream, typename TSpec>
inline int
skipRecord(RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTabComment const & /*tag*/)
{
    return skipLine(reader);
}

template <typename TStream, typename TPass>
inline int
skipRecord(RecordReader<TStream, TPass> & reader, BlastnTabAlignment const & /*tag*/)
{
    return skipLine(reader);
}

// FRAGMENT(batch-read)
template <typename TBlastnTabRecords, typename TStream, typename TSpec>
int read(TBlastnTabRecords & records, RecordReader<TStream, SinglePass<TSpec> > & reader, BlastnTab const & /*tag*/)
{
    BlastnTabAlignmentRecord record;
    while (!atEnd(reader))
    {
        if (nextIs(reader, BlastnTabComment()))
        {
            skipRecord(reader, BlastnTabComment());
            continue;
        }
        if (!nextIs(reader, BlastnTabAlignment()))
            return 1;
        if (readRecord(record, reader, BlastnTabAlignment()) != 0)
            return 1;
        appendValue(records, record);
    }
    return 0;
}

// FRAGMENT(main)
int main(int argc, char const ** argv)
{
    // Process command line arguments, open file.
    if (argc != 2)
    {
        std::cerr << "Incorrect argument count!" << std::endl;
        std::cerr << "USAGE: tutorial_parse_blastn INPUT.txt" << std::endl;
        return 1;
    }
    std::fstream stream(argv[1], std::ios::binary | std::ios::in);
    if (!stream.good())
    {
        std::cerr << "Could not open file " << argv[1] << std::endl;
        return 1;
    }

    // Read file.
    RecordReader<std::fstream, SinglePass<> > reader(stream);
    String<BlastnTabAlignmentRecord> records;
    int res = read(records, reader, BlastnTab());
    if (res != 0)
    {
        std::cerr << "Could not read BLASTN records." << std::endl;
        return 1;
    }

    // Write read records.
    for (unsigned i = 0; i < length(records); ++i)
        write(std::cout, records[i]);

    return 0;
}
<|endoftext|>


<commit_before>#include "dynet/io.h"
#include "dynet/tensor.h"

using namespace std;
using namespace dynet;

TextFileSaver::TextFileSaver(const string & filename, bool append) :
        datastream(filename, append ? ofstream::app : ofstream::out) {
  if(!datastream)
    DYNET_RUNTIME_ERR("Could not write model to " << filename);
}

void TextFileSaver::save(const ParameterCollection & model,
                         const string & key) {
  const ParameterCollectionStorage & storage = model.get_storage();
  if(key.size() == 0) {
    for (auto & p : storage.params) save(*p, key);
    for (auto & p : storage.lookup_params) save(*p, key);
  } else {
    size_t strip_size = model.get_fullname().size();
    for (auto & p : storage.params)
      save(*p, key + p->name.substr(strip_size));
    for (auto & p : storage.lookup_params)
      save(*p, key + p->name.substr(strip_size));
  }
}

void TextFileSaver::save(const Parameter & param,
                         const string & key) {
  save(*param.p, key);
}

void TextFileSaver::save(const LookupParameter & param,
                         const string & key) {
  save(*param.p, key);
}

void TextFileSaver::save(const ParameterStorage & p,
                         const string & key) {
  std::ostringstream buffer;
  buffer << dynet::as_vector(p.values) << endl;
  buffer << dynet::as_vector(p.g) << endl;
  datastream << "#Parameter# " << (key.size() > 0 ? key : p.name) << ' ' << p.dim << ' ' << buffer.str().size() << endl;
  datastream.write(buffer.str().c_str(), buffer.str().size());
}

void TextFileSaver::save(const LookupParameterStorage & p,
                         const string & key) {
  std::ostringstream buffer;
  buffer << dynet::as_vector(p.all_values) << endl;
  buffer << dynet::as_vector(p.all_grads) << endl;
  datastream << "#LookupParameter# " << (key.size() > 0 ? key : p.name) << ' ' << p.all_dim << ' ' << buffer.str().size() << endl;
  datastream.write(buffer.str().c_str(), buffer.str().size());
}

TextFileLoader::TextFileLoader(const string & filename) :
        dataname(filename) { }

void TextFileLoader::populate(ParameterCollection & model, const string & key) {
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  vector<float> values;
  Tensor *value_t, *grad_t;
  size_t param_id = 0, lookup_id = 0;
  ParameterCollectionStorage & storage = model.get_storage();
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim >> byte_count; }
    // Skip ones that don't match
    if(key.size() != 0 && name.substr(0, key.size()) != key) {
      datastream.seekg(datastream.tellg() + byte_count);
      continue;
    // Load a parameter
    } else if(type == "#Parameter#") {
      values.resize(dim.size());
      if(param_id >= storage.params.size())
        DYNET_RUNTIME_ERR("Too many parameters to load in populated model at " << name);
      ParameterStorage & param = *storage.params[param_id++];
      if(param.dim != dim)
        DYNET_RUNTIME_ERR("Dimensions of parameter " << name << " looked up from file (" << dim <<
                            ") do not match parameters to be populated (" << param.dim << ")");
      value_t = &param.values;
      grad_t = &param.g;
    // Load a lookup parameter
    } else if(type == "#LookupParameter#") {
      values.resize(dim.size());
      if(lookup_id >= storage.lookup_params.size())
        DYNET_RUNTIME_ERR("Too many lookup parameters in populated model at " << name);
      LookupParameterStorage & param = *storage.lookup_params[lookup_id++];
      if(param.all_dim != dim)
        DYNET_RUNTIME_ERR("Dimensions of lookup parameter " << name << " lookup up from file (" << dim <<
                            ") do not match parameters to be populated (" << param.all_dim << ")");
      value_t = &param.all_values;
      grad_t = &param.all_grads;
    } else {
      DYNET_RUNTIME_ERR("Bad parameter specification in model: " << line);
    }
    { getline(datastream, line); istringstream iss(line); iss >> values; }
    TensorTools::set_elements(*value_t, values);
    { getline(datastream, line); istringstream iss(line); iss >> values; }
    TensorTools::set_elements(*grad_t, values);
  }
  if(param_id != storage.params.size() || lookup_id != storage.lookup_params.size())
    DYNET_RUNTIME_ERR("Number of parameter/lookup parameter objects loaded from file (" <<
                      param_id << '/' << lookup_id << ") did not match number to be populated (" <<
                      storage.params.size() << '/' << storage.lookup_params.size() << ')');
}

void TextFileLoader::populate(Parameter & param,
                    const string & key) {
  if(key == "")
    DYNET_INVALID_ARG("TextFileLoader.populate() requires non-empty key");
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim >> byte_count; }
    if(type == "#Parameter#" && name == key) {
      if(param.p->dim != dim)
        DYNET_RUNTIME_ERR("Attempted to populate parameter where arguments don't match (" << param.p->dim << " != " << dim << ")");
      vector<float> values(dim.size());
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(param.get_storage().values, values);
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(param.get_storage().g, values);
      return;
    } else {
      datastream.seekg(datastream.tellg() + byte_count);
    }
  }
  DYNET_RUNTIME_ERR("Could not find key " << key << " in the model file");
}

void TextFileLoader::populate(LookupParameter & lookup_param,
                              const string & key) {
  if(key == "")
    DYNET_INVALID_ARG("TextFileLoader.populate() requires non-empty key");
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim >> byte_count; }
    if(type == "#LookupParameter#" && name == key) {
      if(lookup_param.p->all_dim != dim)
        DYNET_RUNTIME_ERR("Attempted to populate lookup parameter where arguments don't match (" << lookup_param.p->all_dim << " != " << dim << ")");
      vector<float> values(dim.size());
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(lookup_param.get_storage().all_values, values);
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(lookup_param.get_storage().all_grads, values);
      return;
    } else {
      datastream.seekg(datastream.tellg() + byte_count);
    }
  }
  DYNET_RUNTIME_ERR("Could not find key " << key << " in the model file");
}

Parameter TextFileLoader::load_param(ParameterCollection & model,
                                     const string & key) {
  if(key == "")
    DYNET_INVALID_ARG("TextFileLoader.load_param() requires non-empty key");
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim; }
    if(type == "#Parameter#" && name == key) {
      Parameter param = model.add_parameters(dim);
      param.get_storage().name = name;
      vector<float> values(dim.size());
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(param.get_storage().values, values);
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(param.get_storage().g, values);
      return param;
    } else {
      datastream.seekg(datastream.tellg() + byte_count);
    }
  }
  DYNET_RUNTIME_ERR("Could not find key " << key << " in the model file");
}

LookupParameter TextFileLoader::load_lookup_param(ParameterCollection & model,
                                                  const string & key) {
  if(key == "")
    DYNET_INVALID_ARG("TextFileLoader.load_lookup_param() requires non-empty key");
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim; }
    if(type == "#LookupParameter#" && name == key) {
      vector<float> values(dim.size());
      size_t size = dim[dim.nd-1]; dim.nd--;
      LookupParameter lookup_param = model.add_lookup_parameters(size, dim);
      lookup_param.get_storage().name = name;
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(lookup_param.get_storage().all_values, values);
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(lookup_param.get_storage().all_grads, values);
      return lookup_param;
    } else {
      datastream.seekg(datastream.tellg() + byte_count);
    }
  }
  DYNET_RUNTIME_ERR("Could not find key " << key << " in the model file");
}
<commit_msg>Add check to avoid key injection<commit_after>#include "dynet/io.h"
#include "dynet/tensor.h"
#include "dynet/except.h"

using namespace std;
using namespace dynet;

bool valid_key(const std::string & s) {
  if (s == "/") return false;
  auto it = std::find_if(s.begin(), s.end(),
                         [] (char ch) { return ch == ' ' || ch == '#';});
  return it == s.end();
}

TextFileSaver::TextFileSaver(const string & filename, bool append) :
        datastream(filename, append ? ofstream::app : ofstream::out) {
  if(!datastream)
    DYNET_RUNTIME_ERR("Could not write model to " << filename);
}

void TextFileSaver::save(const ParameterCollection & model,
                         const string & key) {
  if (!valid_key(key))
    DYNET_INVALID_ARG("Key could not include ' ' or '#': " << key);
  const ParameterCollectionStorage & storage = model.get_storage();
  if(key.size() == 0) {
    for (auto & p : storage.params) save(*p, key);
    for (auto & p : storage.lookup_params) save(*p, key);
  } else {
    size_t strip_size = model.get_fullname().size();
    for (auto & p : storage.params)
      save(*p, key + p->name.substr(strip_size));
    for (auto & p : storage.lookup_params)
      save(*p, key + p->name.substr(strip_size));
  }
}

void TextFileSaver::save(const Parameter & param,
                         const string & key) {
  if (!valid_key(key))
    DYNET_INVALID_ARG("Key could not include ' ' or '#': " << key);
  save(*param.p, key);
}

void TextFileSaver::save(const LookupParameter & param,
                         const string & key) {
  if (!valid_key(key))
    DYNET_INVALID_ARG("Key could not include ' ' or '#': " << key);
  save(*param.p, key);
}

void TextFileSaver::save(const ParameterStorage & p,
                         const string & key) {
  std::ostringstream buffer;
  buffer << dynet::as_vector(p.values) << endl;
  buffer << dynet::as_vector(p.g) << endl;
  datastream << "#Parameter# " << (key.size() > 0 ? key : p.name) << ' '
    << p.dim << ' ' << buffer.str().size() << endl;
  datastream.write(buffer.str().c_str(), buffer.str().size());
}

void TextFileSaver::save(const LookupParameterStorage & p,
                         const string & key) {
  std::ostringstream buffer;
  buffer << dynet::as_vector(p.all_values) << endl;
  buffer << dynet::as_vector(p.all_grads) << endl;
  datastream << "#LookupParameter# " << (key.size() > 0 ? key : p.name) << ' ' << p.all_dim << ' ' << buffer.str().size() << endl;
  datastream.write(buffer.str().c_str(), buffer.str().size());
}

TextFileLoader::TextFileLoader(const string & filename) :
        dataname(filename) { }

void TextFileLoader::populate(ParameterCollection & model, const string & key) {
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  vector<float> values;
  Tensor *value_t, *grad_t;
  size_t param_id = 0, lookup_id = 0;
  ParameterCollectionStorage & storage = model.get_storage();
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim >> byte_count; }
    // Skip ones that don't match
    if(key.size() != 0 && name.substr(0, key.size()) != key) {
      size_t offset = static_cast<size_t>(datastream.tellg()) + byte_count;
      datastream.seekg(offset);
      continue;
    // Load a parameter
    } else if(type == "#Parameter#") {
      values.resize(dim.size());
      if(param_id >= storage.params.size())
        DYNET_RUNTIME_ERR("Too many parameters to load in populated model at " << name);
      ParameterStorage & param = *storage.params[param_id++];
      if(param.dim != dim)
        DYNET_RUNTIME_ERR("Dimensions of parameter " << name << " looked up from file (" << dim <<
                            ") do not match parameters to be populated (" << param.dim << ")");
      value_t = &param.values;
      grad_t = &param.g;
    // Load a lookup parameter
    } else if(type == "#LookupParameter#") {
      values.resize(dim.size());
      if(lookup_id >= storage.lookup_params.size())
        DYNET_RUNTIME_ERR("Too many lookup parameters in populated model at " << name);
      LookupParameterStorage & param = *storage.lookup_params[lookup_id++];
      if(param.all_dim != dim)
        DYNET_RUNTIME_ERR("Dimensions of lookup parameter " << name << " lookup up from file (" << dim <<
                            ") do not match parameters to be populated (" << param.all_dim << ")");
      value_t = &param.all_values;
      grad_t = &param.all_grads;
    } else {
      DYNET_RUNTIME_ERR("Bad parameter specification in model: " << line);
    }
    { getline(datastream, line); istringstream iss(line); iss >> values; }
    TensorTools::set_elements(*value_t, values);
    { getline(datastream, line); istringstream iss(line); iss >> values; }
    TensorTools::set_elements(*grad_t, values);
  }
  if(param_id != storage.params.size() || lookup_id != storage.lookup_params.size())
    DYNET_RUNTIME_ERR("Number of parameter/lookup parameter objects loaded from file (" <<
                      param_id << '/' << lookup_id << ") did not match number to be populated (" <<
                      storage.params.size() << '/' << storage.lookup_params.size() << ')');
}

void TextFileLoader::populate(Parameter & param,
                    const string & key) {
  if(key == "")
    DYNET_INVALID_ARG("TextFileLoader.populate() requires non-empty key");
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim >> byte_count; }
    if(type == "#Parameter#" && name == key) {
      if(param.p->dim != dim)
        DYNET_RUNTIME_ERR("Attempted to populate parameter where arguments don't match (" << param.p->dim << " != " << dim << ")");
      vector<float> values(dim.size());
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(param.get_storage().values, values);
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(param.get_storage().g, values);
      return;
    } else {
      size_t offset = static_cast<size_t>(datastream.tellg()) + byte_count;
      datastream.seekg(offset);
    }
  }
  DYNET_RUNTIME_ERR("Could not find key " << key << " in the model file");
}

void TextFileLoader::populate(LookupParameter & lookup_param,
                              const string & key) {
  if(key == "")
    DYNET_INVALID_ARG("TextFileLoader.populate() requires non-empty key");
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim >> byte_count; }
    if(type == "#LookupParameter#" && name == key) {
      if(lookup_param.p->all_dim != dim)
        DYNET_RUNTIME_ERR("Attempted to populate lookup parameter where arguments don't match (" << lookup_param.p->all_dim << " != " << dim << ")");
      vector<float> values(dim.size());
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(lookup_param.get_storage().all_values, values);
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(lookup_param.get_storage().all_grads, values);
      return;
    } else {
      size_t offset = static_cast<size_t>(datastream.tellg()) + byte_count;
      datastream.seekg(offset);
    }
  }
  DYNET_RUNTIME_ERR("Could not find key " << key << " in the model file");
}

Parameter TextFileLoader::load_param(ParameterCollection & model,
                                     const string & key) {
  if(key == "")
    DYNET_INVALID_ARG("TextFileLoader.load_param() requires non-empty key");
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim >> byte_count; }
    if(type == "#Parameter#" && name == key) {
      Parameter param = model.add_parameters(dim);
      param.get_storage().name = name;
      vector<float> values(dim.size());
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(param.get_storage().values, values);
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(param.get_storage().g, values);
      return param;
    } else {
      size_t offset = static_cast<size_t>(datastream.tellg()) + byte_count;
      datastream.seekg(offset);
    }
  }
  DYNET_RUNTIME_ERR("Could not find key " << key << " in the model file");
}

LookupParameter TextFileLoader::load_lookup_param(ParameterCollection & model,
                                                  const string & key) {
  if(key == "")
    DYNET_INVALID_ARG("TextFileLoader.load_lookup_param() requires non-empty key");
  ifstream datastream(dataname);
  if(!datastream) DYNET_RUNTIME_ERR("Could not read model from " << dataname);
  string line, type, name;
  Dim dim;
  size_t byte_count = 0;
  while(getline(datastream, line)) {
    { istringstream iss(line); iss >> type >> name >> dim >> byte_count; }
    if(type == "#LookupParameter#" && name == key) {
      vector<float> values(dim.size());
      size_t size = dim[dim.nd-1]; dim.nd--;
      LookupParameter lookup_param = model.add_lookup_parameters(size, dim);
      lookup_param.get_storage().name = name;
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(lookup_param.get_storage().all_values, values);
      { getline(datastream, line); istringstream iss(line); iss >> values; }
      TensorTools::set_elements(lookup_param.get_storage().all_grads, values);
      return lookup_param;
    } else {
      size_t offset = static_cast<size_t>(datastream.tellg()) + byte_count;
      datastream.seekg(offset);
    }
  }
  DYNET_RUNTIME_ERR("Could not find key " << key << " in the model file");
}
<|endoftext|>