<commit_before>/*
    This file is part of Akregator.

    Copyright (C) 2004 Sashmit Bhaduri <smt@vfemail.net>

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "tabwidget.h"

#include <QStyle>
#include <QApplication>
#include <QIcon>
#include <QClipboard>
#include <QHash>
#include <QString>
#include <QToolButton>

#include <QMenu>
#include <QStyleOption>

#include <kapplication.h>
#include <kdebug.h>
#include <ktabwidget.h>
#include <ktabbar.h>
#include <kmenu.h>
#include <krun.h>
#include <klocale.h>
#include <khtmlview.h>
#include <khtml_part.h>
#include <kiconloader.h>
#include <ktoolinvocation.h>
#include <kurl.h>
#include <kmimetype.h>
#include <kio/global.h>

#include "actionmanager.h"
#include "akregatorconfig.h"
#include "frame.h"
#include "framemanager.h"
#include "kernel.h"
#include "openurlrequest.h"

#include <cassert>

namespace Akregator {

class TabWidget::Private
{
private:
    TabWidget* const q;

public:
    explicit Private( TabWidget * qq ) : q( qq ) {}

    TabWidget* parent;
    QHash<QWidget*, Frame*> frames;
    QHash<int, Frame*> framesById;
    int currentMaxLength;
    QWidget* currentItem;
    QToolButton* tabsClose;

    uint tabBarWidthForMaxChars(int maxLength);
    void setTitle(const QString &title , QWidget* sender);
    void updateTabBarVisibility();
    Frame* currentFrame();
};

void TabWidget::Private::updateTabBarVisibility()
{
    q->setTabBarHidden( q->count() <= 1 );
}

TabWidget::TabWidget(QWidget * parent)
    :KTabWidget(parent), d(new Private( this ) )
{
    d->parent = this;
    d->currentMaxLength = 30;
    d->currentItem = 0;
    setMinimumSize(250,150);
    setTabReorderingEnabled(false);
    connect( this, SIGNAL( currentChanged(int) ),
             this, SLOT( slotTabChanged(int) ) );
    connect(this, SIGNAL(closeRequest(QWidget*)),
            this, SLOT(slotCloseRequest(QWidget*)));
    setHoverCloseButton(Settings::closeButtonOnTabs());

    d->tabsClose = new QToolButton(this);
    d->tabsClose->setShortcut(QKeySequence("Ctrl+W"));
    connect( d->tabsClose, SIGNAL( clicked() ), this,
            SLOT( slotRemoveCurrentFrame() ) );

    d->tabsClose->setIcon( KIcon( "tab-close" ) );
    d->tabsClose->setEnabled( false );
    d->tabsClose->adjustSize();
    d->tabsClose->setToolTip( i18n("Close the current tab"));
    setCornerWidget( d->tabsClose, Qt::TopRightCorner );
    setTabBarHidden( true );
}

TabWidget::~TabWidget()
{
    delete d;
}

void TabWidget::slotSettingsChanged()
{
    if (hoverCloseButton() != Settings::closeButtonOnTabs())
        setHoverCloseButton(Settings::closeButtonOnTabs());
}

void TabWidget::slotNextTab()
{
    setCurrentIndex((currentIndex()+1) % count());
}

void TabWidget::slotPreviousTab()
{
    if (currentIndex() == 0)
        setCurrentIndex(count()-1);
    else
        setCurrentIndex(currentIndex()-1);
}
void TabWidget::slotSelectFrame(int frameId)
{
    Frame* frame = d->framesById[frameId];
    if (frame && frame != d->currentFrame())
    {
        setCurrentWidget(frame);
        if (frame->part() && frame->part()->widget())
        {
            frame->part()->widget()->setFocus();
        }
        else
        {
            frame->setFocus();
        }
    }
}

void TabWidget::slotAddFrame(Frame* frame)
{
    if (!frame)
        return;
    d->frames.insert(frame, frame);
    d->framesById[frame->id()] = frame;
    addTab(frame, frame->title());
    connect(frame, SIGNAL(signalTitleChanged(Akregator::Frame*,QString)),
            this, SLOT(slotSetTitle(Akregator::Frame*,QString)));
    connect(frame, SIGNAL(signalIconChanged(Akregator::Frame*,QIcon)),
            this, SLOT(slotSetIcon(Akregator::Frame*,QIcon)));

    if(frame->id() > 0) // MainFrame doesn't emit signalPartDestroyed signals, neither should it
        connect(frame, SIGNAL(signalPartDestroyed(int)), this, SLOT(slotRemoveFrame(int)));
    slotSetTitle(frame, frame->title());
}

Frame * TabWidget::Private::currentFrame()
{
    QWidget* w = q->currentWidget();
    assert( frames[w] );
    return w ? frames[w] : 0;
}

void TabWidget::slotTabChanged(int index)
{

    Frame* frame = d->frames[widget(index)];
    d->tabsClose->setEnabled(frame && frame->isRemovable());
    emit signalCurrentFrameChanged(frame ? frame->id() : -1);
}

void TabWidget::tabInserted( int )
{
    d->updateTabBarVisibility();
}

void TabWidget::tabRemoved( int )
{
    d->updateTabBarVisibility();
}

void TabWidget::slotRemoveCurrentFrame()
{
    Frame* const frame = d->currentFrame();
    if (frame)
        emit signalRemoveFrameRequest(frame->id());
}

void TabWidget::slotRemoveFrame(int frameId)
{
    if (!d->framesById.contains(frameId))
        return;
    Frame* f = d->framesById[frameId];
    d->frames.remove(f);
    d->framesById.remove(frameId);
    removeTab(indexOf(f));
    emit signalRemoveFrameRequest(f->id());
    if (d->currentFrame())
      d->setTitle( d->currentFrame()->title(), currentWidget() );
}

// copied wholesale from KonqFrameTabs
uint TabWidget::Private::tabBarWidthForMaxChars( int maxLength )
{
    int hframe, overlap;
    QStyleOption o;
    hframe = parent->tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabHSpace, &o, parent );
    overlap = parent->tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabOverlap, &o, parent );

    QFontMetrics fm = parent->tabBar()->fontMetrics();
    int x = 0;
    for (int i = 0; i < parent->count(); ++i)
    {
        Frame* f = frames[parent->widget(i)];
        QString newTitle = f->title();
        if ( newTitle.length() > maxLength )
            newTitle = newTitle.left( maxLength-3 ) + "...";

        int lw = fm.width( newTitle );
        int iw = parent->tabBar()->tabIcon( i ).pixmap( parent->tabBar()->style()->pixelMetric(
QStyle::PM_SmallIconSize ), QIcon::Normal
).width() + 4;

        x += ( parent->tabBar()->style()->sizeFromContents( QStyle::CT_TabBarTab, &o,
               QSize( qMax( lw + hframe + iw, QApplication::globalStrut().width() ), 0 ), parent ) ).width();
    }
    return x;
}

void TabWidget::slotSetTitle(Frame* frame, const QString& title)
{
    d->setTitle(title, frame);
}

void TabWidget::slotSetIcon(Akregator::Frame* frame, const QIcon& icon)
{
    const int idx = indexOf( frame );
    if ( idx < 0 )
        return;
    setTabIcon( idx, icon );
}

void TabWidget::Private::setTitle( const QString &title, QWidget* sender)
{
    int senderIndex = parent->indexOf(sender);

    parent->setTabToolTip( senderIndex, QString() );

    uint lcw=0, rcw=0;
    int tabBarHeight = parent->tabBar()->sizeHint().height();

    QWidget* leftCorner = parent->cornerWidget( Qt::TopLeftCorner );

    if ( leftCorner  && leftCorner->isVisible() )
        lcw = qMax( leftCorner->width(), tabBarHeight );

    QWidget* rightCorner = parent->cornerWidget( Qt::TopRightCorner );

    if ( rightCorner && rightCorner->isVisible() )
        rcw = qMax( rightCorner->width(), tabBarHeight );
    uint maxTabBarWidth = parent->width() - lcw - rcw;

    int newMaxLength = 30;

    for ( ; newMaxLength > 3; newMaxLength-- )
    {
        if ( tabBarWidthForMaxChars( newMaxLength ) < maxTabBarWidth )
            break;
    }

    QString newTitle = title;
    if ( newTitle.length() > newMaxLength )
    {
        parent->setTabToolTip( senderIndex, newTitle );
        newTitle = newTitle.left( newMaxLength-3 ) + "...";
    }

    newTitle.replace( '&', "&&" );

    if ( parent->tabText(senderIndex) != newTitle )
        parent->setTabText( senderIndex, newTitle );

    if( newMaxLength != currentMaxLength )
    {
        for( int i = 0; i < parent->count(); ++i)
        {
            Frame* f = frames[parent->widget(i)];
            newTitle = f->title();
            int index = parent->indexOf(parent->widget( i ));
            parent->setTabToolTip( index, QString() );

            if ( newTitle.length() > newMaxLength )
            {
                parent->setTabToolTip( index, newTitle );
                newTitle = newTitle.left( newMaxLength-3 ) + "...";
            }

            newTitle.replace( '&', "&&" );
            if ( newTitle != parent->tabText( index ) )
                parent->setTabText( index, newTitle );
        }
        currentMaxLength = newMaxLength;
    }
}

void TabWidget::contextMenu(int i, const QPoint &p)
{
    QWidget* w = ActionManager::getInstance()->container("tab_popup");
    d->currentItem = widget(i);
    //kDebug() << indexOf(d->currentItem);
    // FIXME: do not hardcode index of maintab
    if (w && indexOf(d->currentItem) != 0)
        static_cast<QMenu *>(w)->exec(p);
    d->currentItem = 0;
}

void TabWidget::slotDetachTab()
{
    if (!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();

    Frame* frame = d->frames[d->currentItem];

    if (frame && frame->url().isValid() && frame->isRemovable())
    {
        OpenUrlRequest request;
        request.setUrl(frame->url());
        request.setOptions(OpenUrlRequest::ExternalBrowser);
        emit signalOpenUrlRequest(request);
        slotCloseTab();
    }
}

void TabWidget::slotCopyLinkAddress()
{
    if(!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();
    Frame* frame = d->frames[d->currentItem];

    if (frame && frame->url().isValid())
    {
        KUrl url = frame->url();
        // don't set url to selection as it's a no-no according to a fd.o spec
        //kapp->clipboard()->setText(url.prettyUrl(), QClipboard::Selection);
        kapp->clipboard()->setText(url.prettyUrl(), QClipboard::Clipboard);
    }
}

void TabWidget::slotCloseTab()
{
    if (!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();
    if (d->frames[d->currentItem] == 0 || !d->frames[d->currentItem]->isRemovable() )
        return;

    emit signalRemoveFrameRequest(d->frames[d->currentItem]->id());
}

void TabWidget::initiateDrag(int tab)
{
    Frame* frame = d->frames[widget(tab)];

    if (frame && frame->url().isValid())
    {
        KUrl::List lst;
        lst.append( frame->url() );
        QDrag* drag = new QDrag( this );
        QMimeData *md = new QMimeData;
        drag->setMimeData( md );
        lst.populateMimeData( md );
        drag->setPixmap( KIO::pixmapForUrl( lst.first(), 0, KIconLoader::Small ) );
        drag->start();
    }
}

void TabWidget::slotCloseRequest(QWidget* widget)
{
    if (d->frames[widget])
        emit signalRemoveFrameRequest(d->frames[widget]->id());
}

} // namespace Akregator

#include "tabwidget.moc"
<commit_msg>--deprecated<commit_after>/*
    This file is part of Akregator.

    Copyright (C) 2004 Sashmit Bhaduri <smt@vfemail.net>

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

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.

    As a special exception, permission is given to link this program
    with any edition of Qt, and distribute the resulting executable,
    without including the source code for Qt in the source distribution.
*/

#include "tabwidget.h"

#include <QStyle>
#include <QApplication>
#include <QIcon>
#include <QClipboard>
#include <QHash>
#include <QString>
#include <QToolButton>

#include <QMenu>
#include <QStyleOption>

#include <kapplication.h>
#include <kdebug.h>
#include <ktabwidget.h>
#include <ktabbar.h>
#include <kmenu.h>
#include <krun.h>
#include <klocale.h>
#include <khtmlview.h>
#include <khtml_part.h>
#include <kiconloader.h>
#include <ktoolinvocation.h>
#include <kurl.h>
#include <kmimetype.h>
#include <kio/global.h>

#include "actionmanager.h"
#include "akregatorconfig.h"
#include "frame.h"
#include "framemanager.h"
#include "kernel.h"
#include "openurlrequest.h"

#include <cassert>

namespace Akregator {

class TabWidget::Private
{
private:
    TabWidget* const q;

public:
    explicit Private( TabWidget * qq ) : q( qq ) {}

    TabWidget* parent;
    QHash<QWidget*, Frame*> frames;
    QHash<int, Frame*> framesById;
    int currentMaxLength;
    QWidget* currentItem;
    QToolButton* tabsClose;

    uint tabBarWidthForMaxChars(int maxLength);
    void setTitle(const QString &title , QWidget* sender);
    void updateTabBarVisibility();
    Frame* currentFrame();
};

void TabWidget::Private::updateTabBarVisibility()
{
    q->setTabBarHidden( q->count() <= 1 );
}

TabWidget::TabWidget(QWidget * parent)
    :KTabWidget(parent), d(new Private( this ) )
{
    d->parent = this;
    d->currentMaxLength = 30;
    d->currentItem = 0;
    setMinimumSize(250,150);
    setTabReorderingEnabled(false);
    connect( this, SIGNAL( currentChanged(int) ),
             this, SLOT( slotTabChanged(int) ) );
    connect(this, SIGNAL(closeRequest(QWidget*)),
            this, SLOT(slotCloseRequest(QWidget*)));
    setCloseButtonEnabled(Settings::closeButtonOnTabs());

    d->tabsClose = new QToolButton(this);
    d->tabsClose->setShortcut(QKeySequence("Ctrl+W"));
    connect( d->tabsClose, SIGNAL( clicked() ), this,
            SLOT( slotRemoveCurrentFrame() ) );

    d->tabsClose->setIcon( KIcon( "tab-close" ) );
    d->tabsClose->setEnabled( false );
    d->tabsClose->adjustSize();
    d->tabsClose->setToolTip( i18n("Close the current tab"));
    setCornerWidget( d->tabsClose, Qt::TopRightCorner );
    setTabBarHidden( true );
}

TabWidget::~TabWidget()
{
    delete d;
}

void TabWidget::slotSettingsChanged()
{
    if (hoverCloseButton() != Settings::closeButtonOnTabs())
        setHoverCloseButton(Settings::closeButtonOnTabs());
}

void TabWidget::slotNextTab()
{
    setCurrentIndex((currentIndex()+1) % count());
}

void TabWidget::slotPreviousTab()
{
    if (currentIndex() == 0)
        setCurrentIndex(count()-1);
    else
        setCurrentIndex(currentIndex()-1);
}
void TabWidget::slotSelectFrame(int frameId)
{
    Frame* frame = d->framesById[frameId];
    if (frame && frame != d->currentFrame())
    {
        setCurrentWidget(frame);
        if (frame->part() && frame->part()->widget())
        {
            frame->part()->widget()->setFocus();
        }
        else
        {
            frame->setFocus();
        }
    }
}

void TabWidget::slotAddFrame(Frame* frame)
{
    if (!frame)
        return;
    d->frames.insert(frame, frame);
    d->framesById[frame->id()] = frame;
    addTab(frame, frame->title());
    connect(frame, SIGNAL(signalTitleChanged(Akregator::Frame*,QString)),
            this, SLOT(slotSetTitle(Akregator::Frame*,QString)));
    connect(frame, SIGNAL(signalIconChanged(Akregator::Frame*,QIcon)),
            this, SLOT(slotSetIcon(Akregator::Frame*,QIcon)));

    if(frame->id() > 0) // MainFrame doesn't emit signalPartDestroyed signals, neither should it
        connect(frame, SIGNAL(signalPartDestroyed(int)), this, SLOT(slotRemoveFrame(int)));
    slotSetTitle(frame, frame->title());
}

Frame * TabWidget::Private::currentFrame()
{
    QWidget* w = q->currentWidget();
    assert( frames[w] );
    return w ? frames[w] : 0;
}

void TabWidget::slotTabChanged(int index)
{

    Frame* frame = d->frames[widget(index)];
    d->tabsClose->setEnabled(frame && frame->isRemovable());
    emit signalCurrentFrameChanged(frame ? frame->id() : -1);
}

void TabWidget::tabInserted( int )
{
    d->updateTabBarVisibility();
}

void TabWidget::tabRemoved( int )
{
    d->updateTabBarVisibility();
}

void TabWidget::slotRemoveCurrentFrame()
{
    Frame* const frame = d->currentFrame();
    if (frame)
        emit signalRemoveFrameRequest(frame->id());
}

void TabWidget::slotRemoveFrame(int frameId)
{
    if (!d->framesById.contains(frameId))
        return;
    Frame* f = d->framesById[frameId];
    d->frames.remove(f);
    d->framesById.remove(frameId);
    removeTab(indexOf(f));
    emit signalRemoveFrameRequest(f->id());
    if (d->currentFrame())
      d->setTitle( d->currentFrame()->title(), currentWidget() );
}

// copied wholesale from KonqFrameTabs
uint TabWidget::Private::tabBarWidthForMaxChars( int maxLength )
{
    int hframe, overlap;
    QStyleOption o;
    hframe = parent->tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabHSpace, &o, parent );
    overlap = parent->tabBar()->style()->pixelMetric( QStyle::PM_TabBarTabOverlap, &o, parent );

    QFontMetrics fm = parent->tabBar()->fontMetrics();
    int x = 0;
    for (int i = 0; i < parent->count(); ++i)
    {
        Frame* f = frames[parent->widget(i)];
        QString newTitle = f->title();
        if ( newTitle.length() > maxLength )
            newTitle = newTitle.left( maxLength-3 ) + "...";

        int lw = fm.width( newTitle );
        int iw = parent->tabBar()->tabIcon( i ).pixmap( parent->tabBar()->style()->pixelMetric(
QStyle::PM_SmallIconSize ), QIcon::Normal
).width() + 4;

        x += ( parent->tabBar()->style()->sizeFromContents( QStyle::CT_TabBarTab, &o,
               QSize( qMax( lw + hframe + iw, QApplication::globalStrut().width() ), 0 ), parent ) ).width();
    }
    return x;
}

void TabWidget::slotSetTitle(Frame* frame, const QString& title)
{
    d->setTitle(title, frame);
}

void TabWidget::slotSetIcon(Akregator::Frame* frame, const QIcon& icon)
{
    const int idx = indexOf( frame );
    if ( idx < 0 )
        return;
    setTabIcon( idx, icon );
}

void TabWidget::Private::setTitle( const QString &title, QWidget* sender)
{
    int senderIndex = parent->indexOf(sender);

    parent->setTabToolTip( senderIndex, QString() );

    uint lcw=0, rcw=0;
    int tabBarHeight = parent->tabBar()->sizeHint().height();

    QWidget* leftCorner = parent->cornerWidget( Qt::TopLeftCorner );

    if ( leftCorner  && leftCorner->isVisible() )
        lcw = qMax( leftCorner->width(), tabBarHeight );

    QWidget* rightCorner = parent->cornerWidget( Qt::TopRightCorner );

    if ( rightCorner && rightCorner->isVisible() )
        rcw = qMax( rightCorner->width(), tabBarHeight );
    uint maxTabBarWidth = parent->width() - lcw - rcw;

    int newMaxLength = 30;

    for ( ; newMaxLength > 3; newMaxLength-- )
    {
        if ( tabBarWidthForMaxChars( newMaxLength ) < maxTabBarWidth )
            break;
    }

    QString newTitle = title;
    if ( newTitle.length() > newMaxLength )
    {
        parent->setTabToolTip( senderIndex, newTitle );
        newTitle = newTitle.left( newMaxLength-3 ) + "...";
    }

    newTitle.replace( '&', "&&" );

    if ( parent->tabText(senderIndex) != newTitle )
        parent->setTabText( senderIndex, newTitle );

    if( newMaxLength != currentMaxLength )
    {
        for( int i = 0; i < parent->count(); ++i)
        {
            Frame* f = frames[parent->widget(i)];
            newTitle = f->title();
            int index = parent->indexOf(parent->widget( i ));
            parent->setTabToolTip( index, QString() );

            if ( newTitle.length() > newMaxLength )
            {
                parent->setTabToolTip( index, newTitle );
                newTitle = newTitle.left( newMaxLength-3 ) + "...";
            }

            newTitle.replace( '&', "&&" );
            if ( newTitle != parent->tabText( index ) )
                parent->setTabText( index, newTitle );
        }
        currentMaxLength = newMaxLength;
    }
}

void TabWidget::contextMenu(int i, const QPoint &p)
{
    QWidget* w = ActionManager::getInstance()->container("tab_popup");
    d->currentItem = widget(i);
    //kDebug() << indexOf(d->currentItem);
    // FIXME: do not hardcode index of maintab
    if (w && indexOf(d->currentItem) != 0)
        static_cast<QMenu *>(w)->exec(p);
    d->currentItem = 0;
}

void TabWidget::slotDetachTab()
{
    if (!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();

    Frame* frame = d->frames[d->currentItem];

    if (frame && frame->url().isValid() && frame->isRemovable())
    {
        OpenUrlRequest request;
        request.setUrl(frame->url());
        request.setOptions(OpenUrlRequest::ExternalBrowser);
        emit signalOpenUrlRequest(request);
        slotCloseTab();
    }
}

void TabWidget::slotCopyLinkAddress()
{
    if(!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();
    Frame* frame = d->frames[d->currentItem];

    if (frame && frame->url().isValid())
    {
        KUrl url = frame->url();
        // don't set url to selection as it's a no-no according to a fd.o spec
        //kapp->clipboard()->setText(url.prettyUrl(), QClipboard::Selection);
        kapp->clipboard()->setText(url.prettyUrl(), QClipboard::Clipboard);
    }
}

void TabWidget::slotCloseTab()
{
    if (!d->currentItem || indexOf(d->currentItem) == -1)
        d->currentItem = currentWidget();
    if (d->frames[d->currentItem] == 0 || !d->frames[d->currentItem]->isRemovable() )
        return;

    emit signalRemoveFrameRequest(d->frames[d->currentItem]->id());
}

void TabWidget::initiateDrag(int tab)
{
    Frame* frame = d->frames[widget(tab)];

    if (frame && frame->url().isValid())
    {
        KUrl::List lst;
        lst.append( frame->url() );
        QDrag* drag = new QDrag( this );
        QMimeData *md = new QMimeData;
        drag->setMimeData( md );
        lst.populateMimeData( md );
        drag->setPixmap( KIO::pixmapForUrl( lst.first(), 0, KIconLoader::Small ) );
        drag->start();
    }
}

void TabWidget::slotCloseRequest(QWidget* widget)
{
    if (d->frames[widget])
        emit signalRemoveFrameRequest(d->frames[widget]->id());
}

} // namespace Akregator

#include "tabwidget.moc"
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __CPU_KVM_TIMER_HH__
#define __CPU_KVM_TIMER_HH__

#include <ctime>

#include "cpu/kvm/perfevent.hh"
#include "sim/core.hh"

/**
 * Timer functions to interrupt VM execution after a number of
 * simulation ticks. The timer allows scaling of the host time to take
 * performance differences between the simulated and real CPU into
 * account.
 *
 * The performance scaling factor is ratio between the target's CPI
 * and the host's CPI. It is larger than 1 if the host is faster than
 * the target and lower than 1 if it is slower.
 *
 * When the timer times out, it sends a signal to the thread that
 * started the timer. The signal forces KVM to drop out of the system
 * call that started the guest and hands control to gem5.
 */
class BaseKvmTimer
{
  public:
    /**
     * Setup basic timer functionality shared by all timer
     * implementations.
     *
     * @param signo Signal to deliver
     * @param hostFactor Performance scaling factor
     * @param hostFreq Clock frequency of the host
     */
    BaseKvmTimer(int signo, float hostFactor, Tick hostFreq)
        : signo(signo), _resolution(0),
          hostFactor(hostFactor), hostFreq(hostFreq) {};
    virtual ~BaseKvmTimer() {};

    /**
     * Arm the timer so that it fires after a certain number of ticks.
     *
     * @note A timer implementation is free to convert between
     * simulation ticks and virtualized time using any method it
     * chooses. The accuracy of the timer therefore depends on what it
     * measures, an accurate timer implementation should measure the
     * number of cycles or instructions executed in the guest. If such
     * counters are unavailable, it may fallback to wall clock time.
     *
     * @param ticks Number of ticks until the timer fires
     */
    virtual void arm(Tick ticks) = 0;
    /**
     * Disarm the timer.
     *
     * When this method has returned, the timer may no longer deliver
     * signals upon timeout.
     */
    virtual void disarm() = 0;
    virtual bool expired() {
        return true;
    }

    /**
     * Determine the resolution of the timer in ticks. This method is
     * mainly used to determine the smallest number of ticks the timer
     * can wait before triggering a signal.
     *
     * @return Minimum number of ticks the timer can resolve
     */
    Tick resolution() {
        if (_resolution == 0)
            _resolution = calcResolution();
        return _resolution;
    }

    /**
     * Convert cycles executed on the host into Ticks executed in the
     * simulator. Scales the results using the hostFactor to take CPU
     * performance differences into account.
     *
     * @return Host cycles executed in VM converted to simulation ticks
     */
    Tick ticksFromHostCycles(uint64_t cycles) {
        return cycles * hostFactor * hostFreq;
    }

    /**
     * Convert nanoseconds executed on the host into Ticks executed in
     * the simulator. Scales the results using the hostFactor to take
     * CPU performance differences into account.
     *
     * @return Nanoseconds executed in VM converted to simulation ticks
     */
    Tick ticksFromHostNs(uint64_t ns) {
        return ns * hostFactor * SimClock::Float::ns;
    }

  protected:
    /**
     * Calculate the timer resolution, used by resolution() which
     * caches the result.
     *
     * @return Minimum number of ticks the timer can resolve
     */
    virtual Tick calcResolution() = 0;

    /**
     * Convert a time in simulator ticks to host nanoseconds.
     *
     * @return Simulation ticks converted into nanoseconds on the host
     */
    uint64_t hostNs(Tick ticks) {
        return ticks / (SimClock::Float::ns * hostFactor);
    }

    /**
     * Convert a time in simulator ticks to host cycles
     *
     *
     * @return Simulation ticks converted into CPU cycles on the host
     */
    uint64_t hostCycles(Tick ticks) {
        return ticks / (hostFreq * hostFactor);
    }

    /** Signal to deliver when the timer times out */
    int signo;

  private:
    /** Cached resolution */
    mutable Tick _resolution;

    /** Performance scaling factor */
    float hostFactor;
    /** Host frequency */
    Tick hostFreq;
};

/**
 * Timer based on standard POSIX timers. The POSIX timer API supports
 * several different clock with different characteristics.
 *
 * @note It might be tempting to use
 * CLOCK_(THREAD|PROCESS)_CPUTIME_ID, however, this clock usually has
 * much lower resolution than the real-time clocks.
 */
class PosixKvmTimer : public BaseKvmTimer
{
  public:
    /**
     * @param signo Signal to deliver
     * @param clockID ID of the clock to use
     * @param hostFactor Performance scaling factor
     * @param hostFreq Clock frequency of the host
     */
    PosixKvmTimer(int signo, clockid_t clockID,
                  float hostFactor, Tick hostFreq);
    ~PosixKvmTimer();

    void arm(Tick ticks);
    void disarm();
    bool expired() override;

  protected:
    Tick calcResolution();

  private:
    clockid_t clockID;
    timer_t timer;
    struct itimerspec prevTimerSpec;
};

/**
 * PerfEvent based timer using the host's CPU cycle counter.
 *
 * @warning There is a known problem in some versions of the PerfEvent
 * API that prevents the counter overflow period from being updated
 * reliably, which might break this timer. See PerfKvmCounter::period()
 * for details.
 */
class PerfKvmTimer : public BaseKvmTimer
{
  public:
    /**
     * Create a timer that uses an existing hardware cycle counter.
     *
     * @note The performance counter must be configured for overflow
     * sampling, which in practice means that it must have a non-zero
     * sample period. The initial sample period is ignored since
     * period will be updated when arm() is called.
     *
     * @param ctr Attached performance counter configured for overflow
     *            reporting.
     * @param signo Signal to deliver
     * @param hostFactor Performance scaling factor
     * @param hostFreq Clock frequency of the host
     */
    PerfKvmTimer(PerfKvmCounter &ctr,
                 int signo,
                 float hostFactor, Tick hostFreq);
    ~PerfKvmTimer();

    void arm(Tick ticks);
    void disarm();

  protected:
    Tick calcResolution();

  private:
    PerfKvmCounter &hwOverflow;
};

#endif
<commit_msg>cpu-kvm: Add missing 'override' keyword<commit_after>/*
 * Copyright (c) 2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#ifndef __CPU_KVM_TIMER_HH__
#define __CPU_KVM_TIMER_HH__

#include <ctime>

#include "cpu/kvm/perfevent.hh"
#include "sim/core.hh"

/**
 * Timer functions to interrupt VM execution after a number of
 * simulation ticks. The timer allows scaling of the host time to take
 * performance differences between the simulated and real CPU into
 * account.
 *
 * The performance scaling factor is ratio between the target's CPI
 * and the host's CPI. It is larger than 1 if the host is faster than
 * the target and lower than 1 if it is slower.
 *
 * When the timer times out, it sends a signal to the thread that
 * started the timer. The signal forces KVM to drop out of the system
 * call that started the guest and hands control to gem5.
 */
class BaseKvmTimer
{
  public:
    /**
     * Setup basic timer functionality shared by all timer
     * implementations.
     *
     * @param signo Signal to deliver
     * @param hostFactor Performance scaling factor
     * @param hostFreq Clock frequency of the host
     */
    BaseKvmTimer(int signo, float hostFactor, Tick hostFreq)
        : signo(signo), _resolution(0),
          hostFactor(hostFactor), hostFreq(hostFreq) {};
    virtual ~BaseKvmTimer() {};

    /**
     * Arm the timer so that it fires after a certain number of ticks.
     *
     * @note A timer implementation is free to convert between
     * simulation ticks and virtualized time using any method it
     * chooses. The accuracy of the timer therefore depends on what it
     * measures, an accurate timer implementation should measure the
     * number of cycles or instructions executed in the guest. If such
     * counters are unavailable, it may fallback to wall clock time.
     *
     * @param ticks Number of ticks until the timer fires
     */
    virtual void arm(Tick ticks) = 0;
    /**
     * Disarm the timer.
     *
     * When this method has returned, the timer may no longer deliver
     * signals upon timeout.
     */
    virtual void disarm() = 0;
    virtual bool expired() {
        return true;
    }

    /**
     * Determine the resolution of the timer in ticks. This method is
     * mainly used to determine the smallest number of ticks the timer
     * can wait before triggering a signal.
     *
     * @return Minimum number of ticks the timer can resolve
     */
    Tick resolution() {
        if (_resolution == 0)
            _resolution = calcResolution();
        return _resolution;
    }

    /**
     * Convert cycles executed on the host into Ticks executed in the
     * simulator. Scales the results using the hostFactor to take CPU
     * performance differences into account.
     *
     * @return Host cycles executed in VM converted to simulation ticks
     */
    Tick ticksFromHostCycles(uint64_t cycles) {
        return cycles * hostFactor * hostFreq;
    }

    /**
     * Convert nanoseconds executed on the host into Ticks executed in
     * the simulator. Scales the results using the hostFactor to take
     * CPU performance differences into account.
     *
     * @return Nanoseconds executed in VM converted to simulation ticks
     */
    Tick ticksFromHostNs(uint64_t ns) {
        return ns * hostFactor * SimClock::Float::ns;
    }

  protected:
    /**
     * Calculate the timer resolution, used by resolution() which
     * caches the result.
     *
     * @return Minimum number of ticks the timer can resolve
     */
    virtual Tick calcResolution() = 0;

    /**
     * Convert a time in simulator ticks to host nanoseconds.
     *
     * @return Simulation ticks converted into nanoseconds on the host
     */
    uint64_t hostNs(Tick ticks) {
        return ticks / (SimClock::Float::ns * hostFactor);
    }

    /**
     * Convert a time in simulator ticks to host cycles
     *
     *
     * @return Simulation ticks converted into CPU cycles on the host
     */
    uint64_t hostCycles(Tick ticks) {
        return ticks / (hostFreq * hostFactor);
    }

    /** Signal to deliver when the timer times out */
    int signo;

  private:
    /** Cached resolution */
    mutable Tick _resolution;

    /** Performance scaling factor */
    float hostFactor;
    /** Host frequency */
    Tick hostFreq;
};

/**
 * Timer based on standard POSIX timers. The POSIX timer API supports
 * several different clock with different characteristics.
 *
 * @note It might be tempting to use
 * CLOCK_(THREAD|PROCESS)_CPUTIME_ID, however, this clock usually has
 * much lower resolution than the real-time clocks.
 */
class PosixKvmTimer : public BaseKvmTimer
{
  public:
    /**
     * @param signo Signal to deliver
     * @param clockID ID of the clock to use
     * @param hostFactor Performance scaling factor
     * @param hostFreq Clock frequency of the host
     */
    PosixKvmTimer(int signo, clockid_t clockID,
                  float hostFactor, Tick hostFreq);
    ~PosixKvmTimer();

    void arm(Tick ticks) override;
    void disarm() override;
    bool expired() override;

  protected:
    Tick calcResolution() override;

  private:
    clockid_t clockID;
    timer_t timer;
    struct itimerspec prevTimerSpec;
};

/**
 * PerfEvent based timer using the host's CPU cycle counter.
 *
 * @warning There is a known problem in some versions of the PerfEvent
 * API that prevents the counter overflow period from being updated
 * reliably, which might break this timer. See PerfKvmCounter::period()
 * for details.
 */
class PerfKvmTimer : public BaseKvmTimer
{
  public:
    /**
     * Create a timer that uses an existing hardware cycle counter.
     *
     * @note The performance counter must be configured for overflow
     * sampling, which in practice means that it must have a non-zero
     * sample period. The initial sample period is ignored since
     * period will be updated when arm() is called.
     *
     * @param ctr Attached performance counter configured for overflow
     *            reporting.
     * @param signo Signal to deliver
     * @param hostFactor Performance scaling factor
     * @param hostFreq Clock frequency of the host
     */
    PerfKvmTimer(PerfKvmCounter &ctr,
                 int signo,
                 float hostFactor, Tick hostFreq);
    ~PerfKvmTimer();

    void arm(Tick ticks);
    void disarm();

  protected:
    Tick calcResolution();

  private:
    PerfKvmCounter &hwOverflow;
};

#endif
<|endoftext|>


<commit_before><commit_msg>vcl: make Window::Show() if statement a little easier to read<commit_after><|endoftext|>


<commit_before>/*
 * Copyright 2011-2013 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "BoxImage.h"

#include <gif_lib.h>
#include <jpeglib.h>
#include <png.h>
#include <stdio.h>

#include <GL/gl.h>

#include <boost/bind.hpp>

#include "Bmp.h"

#include "utf.h"
#include "http/HTTPRequest.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

// image/png - 89 50 4E 47 0D 0A 1A 0A
// image/gif - "GIF87a" or "GIF89a"
// image/jpeg - FF D8
// image/x-bmp - "BM"
// image/vnd.microsoft.icon - 00 00 01 00 (.ico), 00 00 02 00 (.cur)

namespace {

unsigned char* readAsPng(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    png_byte header[8];
    if (fread(header, 1, 8, file) != 8 || png_sig_cmp(header, 0, 8))
        return 0;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 0;
    }
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return 0;
    }

    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    unsigned bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    unsigned color_type = png_get_color_type(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_expand_gray_1_2_4_to_8(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type = GL_RGBA;
    }
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    switch (color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_PALETTE:
        format = GL_RGB;
        break;
    default:
        format = GL_RGBA;
        break;
    }
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_bytep data = (png_bytep) malloc(rowbytes * height);
    png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (unsigned i = 0; i < height; i++)
        row_pointers[i] = &data[rowbytes * i];
    png_read_image(png_ptr, row_pointers);
    free(row_pointers);

    png_read_end(png_ptr, end_info);
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return data;
}

unsigned char* readAsJpeg(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    unsigned char sig[2];
    if (fread(sig, 1, sizeof sig, file) != sizeof sig || sig[0] != 0xFF || sig[1] != 0xD8)
        return 0;
    fseek(file, -(sizeof sig), SEEK_CUR);

    JSAMPARRAY img;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);  // TODO: set our own error handdler
    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, true);
    width = cinfo.image_width;
    height = cinfo.image_height;
    jpeg_start_decompress(&cinfo);

    unsigned char* data = (unsigned char*) malloc(height * width * cinfo.out_color_components);
    img = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * height);
    for (unsigned i = 0; i < height; ++i)
        img[i] = (JSAMPROW) &data[cinfo.out_color_components * width * i];

    while(cinfo.output_scanline < cinfo.output_height)
        jpeg_read_scanlines(&cinfo,
                            img + cinfo.output_scanline,
                            cinfo.output_height - cinfo.output_scanline);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(img);

    if (cinfo.out_color_components == 1)
        format = GL_LUMINANCE;
    else
        format = GL_RGB;
    return data;
}

uint16_t readUint16(const char* p)
{
    return static_cast<uint8_t>(p[0]) + (static_cast<uint8_t>(p[1]) << 8);
}

unsigned char* expandColors(unsigned char* dst, unsigned char* src, unsigned count, int transparentIndex, GifColorType* colors)
{
    for (unsigned i = 0; i < count; ++i, ++src) {
        if (*src == transparentIndex) {
            *dst++ = 0;
            *dst++ = 0;
            *dst++ = 0;
            *dst++ = 0;
        } else {
            GifColorType* color = &colors[*src];
            *dst++ = color->Red;
            *dst++ = color->Green;
            *dst++ = color->Blue;
            *dst++ = 255;
        }
    }
    return src;
}

unsigned char* readAsGif(FILE* file, unsigned& width, unsigned& height, unsigned& format, unsigned &frameCount, std::vector<uint16_t>& delays, unsigned& loop)
{
    unsigned char sig[6];
    if (fread(sig, 1, sizeof sig, file) != sizeof sig)
        return 0;
    if (memcmp(sig, GIF87_STAMP, 6) && memcmp(sig, GIF89_STAMP, 6))
        return 0;
    fseek(file, -(sizeof sig), SEEK_CUR);
    long pos = ftell(file);

    int fd = fileno(file);
    lseek(fd, pos, SEEK_SET);
    GifFileType* gif = DGifOpenFileHandle(fd);
    if (!gif)
        return 0;
    if (DGifSlurp(gif) != GIF_OK || gif->ImageCount < 1) {
        DGifCloseFile(gif);
        return 0;
    }

    width = gif->SWidth;
    height = gif->SHeight;
    frameCount = gif->ImageCount;
    loop = 1;
    unsigned char* data = (unsigned char*) malloc(width * height * 4 * frameCount);
    if (!data) {
        DGifCloseFile(gif);
        return 0;
    }

    if (1 < frameCount)
        delays.resize(frameCount, 10);

    format = GL_RGBA;
    for (unsigned frame = 0; frame < frameCount; ++frame) {
        SavedImage* image = &gif->SavedImages[frame];
        int transparentIndex = -1;
        for (int i = 0; i < image->ExtensionBlockCount; ++i) {
            ExtensionBlock* ext = image->ExtensionBlocks + i;
            switch (ext->Function) {
            case GRAPHICS_EXT_FUNC_CODE:
                if (ext->ByteCount == 4) {
                    if ((ext->Bytes[0] & 1))    // transparent?
                        transparentIndex = static_cast<unsigned char>(ext->Bytes[3]);
                    delays[frame] = readUint16(ext->Bytes + 1);
                }
                break;
            case APPLICATION_EXT_FUNC_CODE:
                if (ext->ByteCount == 11 && (!memcmp(ext->Bytes, "NETSCAPE2.0", 11) || !memcmp(ext->Bytes, "ANIMEXTS1.0", 11))) {
                    ++ext;  // Move to the sub-block
                    if (ext->ByteCount == 3) {
                        loop = readUint16(ext->Bytes + 1);
                    }
                }
                break;
            default:
                break;
            }
        }
        unsigned char* p0 = data + frame * width * height * 4;
        if (!gif->Image.Interlace)
            expandColors(p0, image->RasterBits, width * height, transparentIndex, gif->SColorMap->Colors);
        else {
            unsigned char* index = image->RasterBits;
            for (unsigned row = 0; row < height; row += 8)
                index = expandColors(p0 + width * row * 4, index, width, transparentIndex, gif->SColorMap->Colors);
            for (unsigned row = 4; row < height; row += 8)
                index = expandColors(p0 + width * row * 4, index, width, transparentIndex, gif->SColorMap->Colors);
            for (unsigned row = 2; row < height; row += 4)
                index = expandColors(p0 + width * row * 4, index, width, transparentIndex, gif->SColorMap->Colors);
            for (unsigned row = 1; row < height; row += 2)
                index = expandColors(p0 + width * row * 4, index, width, transparentIndex, gif->SColorMap->Colors);
        }
    }
    DGifCloseFile(gif);
    return data;
}

unsigned char* readAsBmp(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    BitmapFileHeader fileHeader;
    if (!fileHeader.read(file))
        return 0;
    BitmapInfoheader header;
    if (!header.read(file))
        return 0;
    RGBQuad colorTable[header.usedColors ? header.usedColors : 1];
    if (0 < header.usedColors && !header.readColorTable(file, colorTable))
        return 0;
    width = header.getWidth();
    height = header.getHeight();
    format = GL_RGBA;
    unsigned char* data = static_cast<unsigned char*>(malloc(width * height * 4));
    if (!data)
        return 0;
    if (std::fseek(file, fileHeader.offset, SEEK_SET) == -1)
        return 0;
    bool result = header.readPixels(file, colorTable, data);
    if (!result) {
        free(data);
        return 0;
    }
    return data;
}

// file must points to BitmapInfoheader
unsigned char* readAsIco(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    BitmapInfoheader header;
    if (!header.read(file))
        return 0;
    RGBQuad colorTable[header.usedColors ? header.usedColors : 1];
    if (0 < header.usedColors && !header.readColorTable(file, colorTable))
        return 0;
    width = header.getWidth();
    height = header.getHeight();
    if (width * 2 == height) {   // has AND plane?
        header.height /= 2;
        height /= 2;
    }
    format = GL_RGBA;
    unsigned char* data = static_cast<unsigned char*>(malloc(width * height * 4));
    if (!data)
        return 0;
    // TODO: Process AND plane.
    // TODO: Support JPEG and PNG.
    bool result = header.readPixels(file, colorTable, data);
    if (!result) {
        free(data);
        return 0;
    }
    return data;
}

}  // namespace

BoxImage::BoxImage(unsigned repeat) :
    state(Unavailable),
    flags(0),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(repeat),
    format(GL_RGBA),
    frameCount(1),
    delays(1),
    total(0.0f)
{
}

void BoxImage::open(FILE* file)
{
    assert(file);
    long pos = ftell(file);
    pixels = readAsIco(file, naturalWidth, naturalHeight, format);
    if (!pixels) {
        fseek(file, pos, SEEK_SET);
        pixels = readAsPng(file, naturalWidth, naturalHeight, format);
    }
    if (!pixels) {
        fseek(file, pos, SEEK_SET);
        pixels = readAsJpeg(file, naturalWidth, naturalHeight, format);
    }
    if (!pixels) {
        fseek(file, pos, SEEK_SET);
        pixels = readAsGif(file, naturalWidth, naturalHeight, format, frameCount, delays, loop);
    }
    if (!pixels) {
        fseek(file, pos, SEEK_SET);
        pixels = readAsBmp(file, naturalWidth, naturalHeight, format);
    }
    if (!pixels) {
        state = Broken;
        return;
    }
    state = CompletelyAvailable;
    total = 0.0f;
    for (size_t i = 0; i < delays.size(); ++i)
        total += delays[i];
}

unsigned BoxImage::getCurrentFrame(unsigned t, unsigned& delay, unsigned start)
{
    if (frameCount <= 1 || total == 0.0f)
        return 0;
    if (loop) {
        t -= start;
        if (total * loop <= t)
            return 0;
    }
    t %= total;
    unsigned d = 0.0f;
    for (unsigned i = 0; i < delays.size(); ++i) {
        d += delays[i];
        if (t < d) {
            delay = d - t;
            return i;
        }
    }
    return 0;
}

//
// HttpRequest
//

BoxImage* HttpRequest::getBoxImage(unsigned repeat)
{
    if (!boxImage)
        boxImage = new(std::nothrow) BoxImage(repeat);
    if (!boxImage)
        return 0;

    switch (getReadyState()) {
    case UNSENT:
        boxImage->setState(BoxImage::Unavailable);
        break;
    case OPENED:
    case HEADERS_RECEIVED:
    case LOADING:
    case COMPLETE:
        boxImage->setState(BoxImage::Sent);
        break;
    case DONE:
        if (boxImage->getState() < BoxImage::PartiallyAvailable) {
            if (getError()) {
                boxImage->setState(BoxImage::Unavailable);
                break;
            }
            if (FILE* file = openFile()) {
                boxImage->open(file);
                fclose(file);
            }
        }
        break;
    default:
        boxImage->setState(BoxImage::Unavailable);
        break;
    }
    return boxImage;
}

}}}}  // org::w3c::dom::bootstrap
<commit_msg>src/css/BoxImage.cpp (readAsGif) : Fix bugs<commit_after>/*
 * Copyright 2011-2013 Esrille Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "BoxImage.h"

#include <gif_lib.h>
#include <jpeglib.h>
#include <png.h>
#include <stdio.h>

#include <GL/gl.h>

#include <boost/bind.hpp>

#include "Bmp.h"

#include "utf.h"
#include "http/HTTPRequest.h"

namespace org { namespace w3c { namespace dom { namespace bootstrap {

// image/png - 89 50 4E 47 0D 0A 1A 0A
// image/gif - "GIF87a" or "GIF89a"
// image/jpeg - FF D8
// image/x-bmp - "BM"
// image/vnd.microsoft.icon - 00 00 01 00 (.ico), 00 00 02 00 (.cur)

namespace {

unsigned char* readAsPng(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    png_byte header[8];
    if (fread(header, 1, 8, file) != 8 || png_sig_cmp(header, 0, 8))
        return 0;

    png_structp png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    if (!png_ptr)
        return 0;
    png_infop info_ptr = png_create_info_struct(png_ptr);
    if (!info_ptr) {
        png_destroy_read_struct(&png_ptr, NULL, NULL);
        return 0;
    }
    png_infop end_info = png_create_info_struct(png_ptr);
    if (!end_info) {
        png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
        return 0;
    }
    if (setjmp(png_jmpbuf(png_ptr))) {
        png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
        return 0;
    }

    png_init_io(png_ptr, file);
    png_set_sig_bytes(png_ptr, 8);

    png_read_info(png_ptr, info_ptr);

    width = png_get_image_width(png_ptr, info_ptr);
    height = png_get_image_height(png_ptr, info_ptr);
    unsigned bit_depth = png_get_bit_depth(png_ptr, info_ptr);
    unsigned color_type = png_get_color_type(png_ptr, info_ptr);

    if (color_type == PNG_COLOR_TYPE_PALETTE)
        png_set_palette_to_rgb(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        png_set_expand_gray_1_2_4_to_8(png_ptr);
    if (color_type == PNG_COLOR_TYPE_GRAY || color_type == PNG_COLOR_TYPE_GRAY_ALPHA)
        png_set_gray_to_rgb(png_ptr);
    if (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)) {
        png_set_tRNS_to_alpha(png_ptr);
        color_type = GL_RGBA;
    }
    if (bit_depth == 16)
        png_set_strip_16(png_ptr);
    switch (color_type) {
    case PNG_COLOR_TYPE_RGB:
    case PNG_COLOR_TYPE_GRAY:
    case PNG_COLOR_TYPE_PALETTE:
        format = GL_RGB;
        break;
    default:
        format = GL_RGBA;
        break;
    }
    png_set_interlace_handling(png_ptr);

    png_read_update_info(png_ptr, info_ptr);

    unsigned rowbytes = png_get_rowbytes(png_ptr, info_ptr);
    png_bytep data = (png_bytep) malloc(rowbytes * height);
    png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
    for (unsigned i = 0; i < height; i++)
        row_pointers[i] = &data[rowbytes * i];
    png_read_image(png_ptr, row_pointers);
    free(row_pointers);

    png_read_end(png_ptr, end_info);
    png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);

    return data;
}

unsigned char* readAsJpeg(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    unsigned char sig[2];
    if (fread(sig, 1, sizeof sig, file) != sizeof sig || sig[0] != 0xFF || sig[1] != 0xD8)
        return 0;
    fseek(file, -(sizeof sig), SEEK_CUR);

    JSAMPARRAY img;
    struct jpeg_decompress_struct cinfo;
    struct jpeg_error_mgr jerr;

    cinfo.err = jpeg_std_error(&jerr);  // TODO: set our own error handdler
    jpeg_create_decompress(&cinfo);

    jpeg_stdio_src(&cinfo, file);
    jpeg_read_header(&cinfo, true);
    width = cinfo.image_width;
    height = cinfo.image_height;
    jpeg_start_decompress(&cinfo);

    unsigned char* data = (unsigned char*) malloc(height * width * cinfo.out_color_components);
    img = (JSAMPARRAY) malloc(sizeof(JSAMPROW) * height);
    for (unsigned i = 0; i < height; ++i)
        img[i] = (JSAMPROW) &data[cinfo.out_color_components * width * i];

    while(cinfo.output_scanline < cinfo.output_height)
        jpeg_read_scanlines(&cinfo,
                            img + cinfo.output_scanline,
                            cinfo.output_height - cinfo.output_scanline);
    jpeg_finish_decompress(&cinfo);
    jpeg_destroy_decompress(&cinfo);

    free(img);

    if (cinfo.out_color_components == 1)
        format = GL_LUMINANCE;
    else
        format = GL_RGB;
    return data;
}

uint16_t readUint16(const char* p)
{
    return static_cast<uint8_t>(p[0]) + (static_cast<uint8_t>(p[1]) << 8);
}

unsigned char* expandColors(unsigned char* dst, unsigned char* src, unsigned count, int transparentIndex, GifColorType* colors)
{
    for (unsigned i = 0; i < count; ++i, ++src) {
        if (*src == transparentIndex) {
            *dst++ = 0;
            *dst++ = 0;
            *dst++ = 0;
            *dst++ = 0;
        } else {
            GifColorType* color = &colors[*src];
            *dst++ = color->Red;
            *dst++ = color->Green;
            *dst++ = color->Blue;
            *dst++ = 255;
        }
    }
    return src;
}

unsigned char* readAsGif(FILE* file, unsigned& width, unsigned& height, unsigned& format, unsigned &frameCount, std::vector<uint16_t>& delays, unsigned& loop)
{
    unsigned char sig[6];
    if (fread(sig, 1, sizeof sig, file) != sizeof sig)
        return 0;
    if (memcmp(sig, GIF87_STAMP, 6) && memcmp(sig, GIF89_STAMP, 6))
        return 0;
    fseek(file, -(sizeof sig), SEEK_CUR);
    long pos = ftell(file);

    int fd = fileno(file);
    lseek(fd, pos, SEEK_SET);
    GifFileType* gif = DGifOpenFileHandle(fd);
    if (!gif)
        return 0;
    if (DGifSlurp(gif) != GIF_OK || gif->ImageCount < 1) {
        DGifCloseFile(gif);
        return 0;
    }

    width = gif->SWidth;
    height = gif->SHeight;
    frameCount = gif->ImageCount;
    loop = 1;
    unsigned char* data = (unsigned char*) malloc(width * height * 4 * frameCount);
    if (!data) {
        DGifCloseFile(gif);
        return 0;
    }

    if (1 < frameCount)
        delays.resize(frameCount, 10);

    format = GL_RGBA;
    for (unsigned frame = 0; frame < frameCount; ++frame) {
        SavedImage* image = &gif->SavedImages[frame];
        int transparentIndex = -1;
        for (int i = 0; i < image->ExtensionBlockCount; ++i) {
            ExtensionBlock* ext = image->ExtensionBlocks + i;
            switch (ext->Function) {
            case GRAPHICS_EXT_FUNC_CODE:
                if (ext->ByteCount == 4) {
                    if ((ext->Bytes[0] & 1))    // transparent?
                        transparentIndex = static_cast<unsigned char>(ext->Bytes[3]);
                    delays[frame] = readUint16(ext->Bytes + 1);
                }
                break;
            case APPLICATION_EXT_FUNC_CODE:
                if (ext->ByteCount == 11 && (!memcmp(ext->Bytes, "NETSCAPE2.0", 11) || !memcmp(ext->Bytes, "ANIMEXTS1.0", 11))) {
                    ++ext;  // Move to the sub-block
                    if (ext->ByteCount == 3) {
                        loop = readUint16(ext->Bytes + 1);
                    }
                }
                break;
            default:
                break;
            }
        }
        unsigned char* p0 = data + frame * width * height * 4;
        ColorMapObject* colorMap = image->ImageDesc.ColorMap ? image->ImageDesc.ColorMap : gif->SColorMap;
        if (!image->ImageDesc.Interlace)
            expandColors(p0, image->RasterBits, width * height, transparentIndex, colorMap->Colors);
        else {
            unsigned char* index = image->RasterBits;
            for (unsigned row = 0; row < height; row += 8)
                index = expandColors(p0 + width * row * 4, index, width, transparentIndex, colorMap->Colors);
            for (unsigned row = 4; row < height; row += 8)
                index = expandColors(p0 + width * row * 4, index, width, transparentIndex, colorMap->Colors);
            for (unsigned row = 2; row < height; row += 4)
                index = expandColors(p0 + width * row * 4, index, width, transparentIndex, colorMap->Colors);
            for (unsigned row = 1; row < height; row += 2)
                index = expandColors(p0 + width * row * 4, index, width, transparentIndex, colorMap->Colors);
        }
    }
    DGifCloseFile(gif);
    return data;
}

unsigned char* readAsBmp(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    BitmapFileHeader fileHeader;
    if (!fileHeader.read(file))
        return 0;
    BitmapInfoheader header;
    if (!header.read(file))
        return 0;
    RGBQuad colorTable[header.usedColors ? header.usedColors : 1];
    if (0 < header.usedColors && !header.readColorTable(file, colorTable))
        return 0;
    width = header.getWidth();
    height = header.getHeight();
    format = GL_RGBA;
    unsigned char* data = static_cast<unsigned char*>(malloc(width * height * 4));
    if (!data)
        return 0;
    if (std::fseek(file, fileHeader.offset, SEEK_SET) == -1)
        return 0;
    bool result = header.readPixels(file, colorTable, data);
    if (!result) {
        free(data);
        return 0;
    }
    return data;
}

// file must points to BitmapInfoheader
unsigned char* readAsIco(FILE* file, unsigned& width, unsigned& height, unsigned& format)
{
    BitmapInfoheader header;
    if (!header.read(file))
        return 0;
    RGBQuad colorTable[header.usedColors ? header.usedColors : 1];
    if (0 < header.usedColors && !header.readColorTable(file, colorTable))
        return 0;
    width = header.getWidth();
    height = header.getHeight();
    if (width * 2 == height) {   // has AND plane?
        header.height /= 2;
        height /= 2;
    }
    format = GL_RGBA;
    unsigned char* data = static_cast<unsigned char*>(malloc(width * height * 4));
    if (!data)
        return 0;
    // TODO: Process AND plane.
    // TODO: Support JPEG and PNG.
    bool result = header.readPixels(file, colorTable, data);
    if (!result) {
        free(data);
        return 0;
    }
    return data;
}

}  // namespace

BoxImage::BoxImage(unsigned repeat) :
    state(Unavailable),
    flags(0),
    pixels(0),
    naturalWidth(0),
    naturalHeight(0),
    repeat(repeat),
    format(GL_RGBA),
    frameCount(1),
    delays(1),
    total(0.0f)
{
}

void BoxImage::open(FILE* file)
{
    assert(file);
    long pos = ftell(file);
    pixels = readAsIco(file, naturalWidth, naturalHeight, format);
    if (!pixels) {
        fseek(file, pos, SEEK_SET);
        pixels = readAsPng(file, naturalWidth, naturalHeight, format);
    }
    if (!pixels) {
        fseek(file, pos, SEEK_SET);
        pixels = readAsJpeg(file, naturalWidth, naturalHeight, format);
    }
    if (!pixels) {
        fseek(file, pos, SEEK_SET);
        pixels = readAsGif(file, naturalWidth, naturalHeight, format, frameCount, delays, loop);
    }
    if (!pixels) {
        fseek(file, pos, SEEK_SET);
        pixels = readAsBmp(file, naturalWidth, naturalHeight, format);
    }
    if (!pixels) {
        state = Broken;
        return;
    }
    state = CompletelyAvailable;
    total = 0.0f;
    for (size_t i = 0; i < delays.size(); ++i)
        total += delays[i];
}

unsigned BoxImage::getCurrentFrame(unsigned t, unsigned& delay, unsigned start)
{
    if (frameCount <= 1 || total == 0.0f)
        return 0;
    if (loop) {
        t -= start;
        if (total * loop <= t)
            return 0;
    }
    t %= total;
    unsigned d = 0.0f;
    for (unsigned i = 0; i < delays.size(); ++i) {
        d += delays[i];
        if (t < d) {
            delay = d - t;
            return i;
        }
    }
    return 0;
}

//
// HttpRequest
//

BoxImage* HttpRequest::getBoxImage(unsigned repeat)
{
    if (!boxImage)
        boxImage = new(std::nothrow) BoxImage(repeat);
    if (!boxImage)
        return 0;

    switch (getReadyState()) {
    case UNSENT:
        boxImage->setState(BoxImage::Unavailable);
        break;
    case OPENED:
    case HEADERS_RECEIVED:
    case LOADING:
    case COMPLETE:
        boxImage->setState(BoxImage::Sent);
        break;
    case DONE:
        if (boxImage->getState() < BoxImage::PartiallyAvailable) {
            if (getError()) {
                boxImage->setState(BoxImage::Unavailable);
                break;
            }
            if (FILE* file = openFile()) {
                boxImage->open(file);
                fclose(file);
            }
        }
        break;
    default:
        boxImage->setState(BoxImage::Unavailable);
        break;
    }
    return boxImage;
}

}}}}  // org::w3c::dom::bootstrap
<|endoftext|>


<commit_before>#include <iostream>
#include <cstdlib>
#include "sudoku.h"

Sudoku::Sudoku(std::istream& stream)
: answer{}
{
    for (int r = 0; r < BOARD_SIZE; ++r)
    {
        for (int c = 0; c < BOARD_SIZE; ++c)
        {
            int v = stream.get();
            for ( ; ; v = stream.get())
            {
                if (v == std::char_traits<char>::eof())
                {
                    v = 0;
                    break;
                }
                if (v == '0' || v == '.')
                {
                    v = 0;
                    break;
                }
                if ('1' <= v && v <= '9')
                {
                    v -= '0';
                    break;
                }
            }

            game_board[r][c] = v;
        }
    }
    if (!solve()) // no solutions
    {
    }
}

void Sudoku::show_game()
{
    std::cout << "+";
    for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
    {
        for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
        {
            std::cout << "--";
        }
        std::cout << "-+";
    }
    std::cout << std::endl;

    for (int box_r = 0; box_r < BOARD_SIZE; box_r += BOX_HEIGHT)
    {
        for (int r = box_r; r < box_r + BOX_HEIGHT; ++r)
        {
            std::cout << "|";
            for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
            {
                for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
                {
                    std::cout << " " << game_board[r][c];
                }
                std::cout << " |";
            }
            std::cout << std::endl;
        }

        std::cout << "+";
        for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
        {
            for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
            {
                std::cout << "--";
            }
            std::cout << "-+";
        }
        std::cout << std::endl;
    }
}

void Sudoku::show_answer()
{
    std::cout << "+";
    for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
    {
        for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
        {
            std::cout << "--";
        }
        std::cout << "-+";
    }
    std::cout << std::endl;

    for (int box_r = 0; box_r < BOARD_SIZE; box_r += BOX_HEIGHT)
    {
        for (int r = box_r; r < box_r + BOX_HEIGHT; ++r)
        {
            std::cout << "|";
            for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
            {
                for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
                {
                    std::cout << " " << answer[r][c];
                }
                std::cout << " |";
            }
            std::cout << std::endl;
        }

        std::cout << "+";
        for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
        {
            for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
            {
                std::cout << "--";
            }
            std::cout << "-+";
        }
        std::cout << std::endl;
    }
}

// bool Sudoku::validate_at(int row, int col, int value)
// {
//     return answer[row][col] == value;
// }

bool Sudoku::is_complete()
{
    for (int r = 0; r < BOARD_SIZE; ++r)
    {
        for (int c = 0; c < BOARD_SIZE; ++c)
        {
            if (game_board[r][c] != answer[r][c])
            {
                return false;
            }
        }
    }
    return true;
}

bool Sudoku::solve()
{
    return SudokuSolver::solve(game_board, answer);
}

void Sudoku::write_game_board(int row, int col, int value)
{
    game_board[row][col] = value;
}

void Sudoku::erase_game_board(int row, int col)
{
    game_board[row][col] = EMPTY_CELL;
}

void Sudoku::hint()
{
    int row = std::rand() % BOARD_SIZE;
    int col = std::rand() % BOARD_SIZE;

    std::cout << "Correct answer at ("
        << row << ", "
        << col
    << ") is " << answer[row][col] << "." << std::endl;

    if (answer[row][col] == game_board[row][col])
    {
        std::cout << "Your answer is correct." << std::endl;
    }
}

SudokuSolver::SudokuSolver(int const in_board[BOARD_SIZE][BOARD_SIZE])
: solution_found(false)
, eliminated{}
, num_eliminated{}
{
    for (int r = 0; r < BOARD_SIZE; ++r)
    {
        for (int c = 0; c < BOARD_SIZE; ++c)
        {
            int v = in_board[r][c] - 1;
            if (v != -1)
            {
                if (!assign({r, c}, v))
                {
                    return;
                }
            }
        }
    }

    bool should_backtrack = false;
    for ( ; ; )
    {
        // assining target & value [0..BOARD_SIZE)
        Position p;
        int v;

        if (should_backtrack)
        {
            if (call_stack.empty())
            {
                return;
            }
            CallStackRecord rec_c = backtrack();
            p = rec_c.position;
            for (v = rec_c.value + 1; v < BOARD_SIZE; ++v)
            {
                if (!eliminated[p.row][p.col][v])
                {
                    break;
                }
            }
            if (v == BOARD_SIZE)
            {
                // should_backtrack = true;
                continue;
            }
        }
        else
        {
            v = 0;
            bool found_target = false;
            int minimum_size = BOARD_SIZE + 1;
            for (int r = 0; r < BOARD_SIZE; ++r)
            {
                for (int c = 0; c < BOARD_SIZE; ++c)
                {
                    if (num_eliminated[r][c] < BOARD_SIZE - 1)
                    {
                        int size = BOARD_SIZE - num_eliminated[r][c];
                        if (size < minimum_size)
                        {
                            found_target = true;
                            p = Position {r, c};
                            minimum_size = size;
                        }
                        break;
                    }
                }
            }
            if (!found_target)
            {
                solution_found = true;
                return;
            }
        }

        call_stack.push_back({p, v, history.size()});
        should_backtrack = false;
        if (!assign(p, v))
        {
            should_backtrack = true;
        }
    }
}

bool SudokuSolver::assign(Position p, int v)
{
    for (int v_el = 0; v_el < BOARD_SIZE; ++v_el)
    {
        if (v_el != v)
        {
            if (!eliminate(p, v_el))
            {
                elimination_stack.clear();
                return false;
            }
        }
    }

    while (!elimination_stack.empty())
    {
        HistoryRecord rec = elimination_stack.back();
        elimination_stack.pop_back();
        Position p = rec.position;
        int v = rec.value;
        int r = p.row;
        int c = p.col;
        for (int house_type = 0; house_type < 3; ++house_type)
        {
            // house size
            int lr =    house_type == 0 ?  BOARD_SIZE
                   :    house_type == 1 ?  BOX_WIDTH
                   : /* house_type == 2 */ 1;
            int lc = BOARD_SIZE / lr;

            // house position
            int br = r / lr * lr;
            int bc = c / lc * lc;

            for (int dr = 0; dr < lr; ++dr)
            {
                for (int dc = 0; dc < lc; ++dc)
                {
                    int nr = br + dr;
                    int nc = bc + dc;
                    if (r != nr || c != nc)
                    {
                        if (!eliminate({nr, nc}, v))
                        {
                            elimination_stack.clear();
                            return false;
                        }
                    }
                }
            }
        }
    }

    return true;
}

bool SudokuSolver::eliminate(Position p, int v)
{
    if (!eliminated[p.row][p.col][v])
    {
        eliminated[p.row][p.col][v] = true;
        ++num_eliminated[p.row][p.col];
        history.push_back({p, v});
        if (num_eliminated[p.row][p.col] == BOARD_SIZE - 1)
        {
            for (int v_p = 0; v_p < BOARD_SIZE; ++v_p)
            {
                if (!eliminated[p.row][p.col][v_p])
                {
                    elimination_stack.push_back({p, v_p});
                }
            }
        }
        else if (num_eliminated[p.row][p.col] == BOARD_SIZE)
        {
            return false;
        }
    }
    return true;
}

CallStackRecord SudokuSolver::backtrack()
{
    CallStackRecord rec_c = call_stack.back();
    call_stack.pop_back();
    while (history.size() > rec_c.history_length)
    {
        HistoryRecord rec_h = history.back();
        history.pop_back();
        int r = rec_h.position.row;
        int c = rec_h.position.col;
        eliminated[r][c][rec_h.value] = false;
        --num_eliminated[r][c];
    }
    return rec_c;
}

bool SudokuSolver::solve(int const in_board[BOARD_SIZE][BOARD_SIZE], int out_board[BOARD_SIZE][BOARD_SIZE])
{
    SudokuSolver solver = in_board;

    if (!solver.solution_found)
    {
        return false;
    }

    for (int r = 0; r < BOARD_SIZE; ++r)
    {
        for (int c = 0; c < BOARD_SIZE; ++c)
        {
            for (int v = 0; v < BOARD_SIZE; ++v)
            {
                if (!solver.eliminated[r][c][v])
                {
                    out_board[r][c] = v + 1;
                }
            }
        }
    }

    return true;
}
<commit_msg>Use EMPTY_CELL macro constant<commit_after>#include <iostream>
#include <cstdlib>
#include "sudoku.h"

Sudoku::Sudoku(std::istream& stream)
: answer{}
{
    for (int r = 0; r < BOARD_SIZE; ++r)
    {
        for (int c = 0; c < BOARD_SIZE; ++c)
        {
            int v = stream.get();
            for ( ; ; v = stream.get())
            {
                if (v == std::char_traits<char>::eof())
                {
                    v = EMPTY_CELL;
                    break;
                }
                if (v == '0' || v == '.')
                {
                    v = EMPTY_CELL;
                    break;
                }
                if ('1' <= v && v <= '9')
                {
                    v -= '0';
                    break;
                }
            }

            game_board[r][c] = v;
        }
    }
    if (!solve()) // no solutions
    {
    }
}

void Sudoku::show_game()
{
    std::cout << "+";
    for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
    {
        for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
        {
            std::cout << "--";
        }
        std::cout << "-+";
    }
    std::cout << std::endl;

    for (int box_r = 0; box_r < BOARD_SIZE; box_r += BOX_HEIGHT)
    {
        for (int r = box_r; r < box_r + BOX_HEIGHT; ++r)
        {
            std::cout << "|";
            for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
            {
                for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
                {
                    std::cout << " " << game_board[r][c];
                }
                std::cout << " |";
            }
            std::cout << std::endl;
        }

        std::cout << "+";
        for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
        {
            for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
            {
                std::cout << "--";
            }
            std::cout << "-+";
        }
        std::cout << std::endl;
    }
}

void Sudoku::show_answer()
{
    std::cout << "+";
    for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
    {
        for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
        {
            std::cout << "--";
        }
        std::cout << "-+";
    }
    std::cout << std::endl;

    for (int box_r = 0; box_r < BOARD_SIZE; box_r += BOX_HEIGHT)
    {
        for (int r = box_r; r < box_r + BOX_HEIGHT; ++r)
        {
            std::cout << "|";
            for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
            {
                for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
                {
                    std::cout << " " << answer[r][c];
                }
                std::cout << " |";
            }
            std::cout << std::endl;
        }

        std::cout << "+";
        for (int box_c = 0; box_c < BOARD_SIZE; box_c += BOX_WIDTH)
        {
            for (int c = box_c; c < box_c + BOX_WIDTH; ++c)
            {
                std::cout << "--";
            }
            std::cout << "-+";
        }
        std::cout << std::endl;
    }
}

// bool Sudoku::validate_at(int row, int col, int value)
// {
//     return answer[row][col] == value;
// }

bool Sudoku::is_complete()
{
    for (int r = 0; r < BOARD_SIZE; ++r)
    {
        for (int c = 0; c < BOARD_SIZE; ++c)
        {
            if (game_board[r][c] != answer[r][c])
            {
                return false;
            }
        }
    }
    return true;
}

bool Sudoku::solve()
{
    return SudokuSolver::solve(game_board, answer);
}

void Sudoku::write_game_board(int row, int col, int value)
{
    game_board[row][col] = value;
}

void Sudoku::erase_game_board(int row, int col)
{
    game_board[row][col] = EMPTY_CELL;
}

void Sudoku::hint()
{
    int row = std::rand() % BOARD_SIZE;
    int col = std::rand() % BOARD_SIZE;

    std::cout << "Correct answer at ("
        << row << ", "
        << col
    << ") is " << answer[row][col] << "." << std::endl;

    if (answer[row][col] == game_board[row][col])
    {
        std::cout << "Your answer is correct." << std::endl;
    }
}

SudokuSolver::SudokuSolver(int const in_board[BOARD_SIZE][BOARD_SIZE])
: solution_found(false)
, eliminated{}
, num_eliminated{}
{
    for (int r = 0; r < BOARD_SIZE; ++r)
    {
        for (int c = 0; c < BOARD_SIZE; ++c)
        {
            int v = in_board[r][c];
            if (v != EMPTY_CELL)
            {
                if (!assign({r, c}, v - 1))
                {
                    return;
                }
            }
        }
    }

    bool should_backtrack = false;
    for ( ; ; )
    {
        // assining target & value
        Position p;
        int v;

        if (should_backtrack)
        {
            if (call_stack.empty())
            {
                return;
            }
            CallStackRecord rec_c = backtrack();
            p = rec_c.position;
            for (v = rec_c.value + 1; v < BOARD_SIZE; ++v)
            {
                if (!eliminated[p.row][p.col][v])
                {
                    break;
                }
            }
            if (v == BOARD_SIZE)
            {
                // should_backtrack = true;
                continue;
            }
        }
        else
        {
            v = 0;
            bool found_target = false;
            int minimum_size = BOARD_SIZE + 1;
            for (int r = 0; r < BOARD_SIZE; ++r)
            {
                for (int c = 0; c < BOARD_SIZE; ++c)
                {
                    if (num_eliminated[r][c] < BOARD_SIZE - 1)
                    {
                        int size = BOARD_SIZE - num_eliminated[r][c];
                        if (size < minimum_size)
                        {
                            found_target = true;
                            p = Position {r, c};
                            minimum_size = size;
                        }
                        break;
                    }
                }
            }
            if (!found_target)
            {
                solution_found = true;
                return;
            }
        }

        call_stack.push_back({p, v, history.size()});
        should_backtrack = false;
        if (!assign(p, v))
        {
            should_backtrack = true;
        }
    }
}

bool SudokuSolver::assign(Position p, int v)
{
    for (int v_el = 0; v_el < BOARD_SIZE; ++v_el)
    {
        if (v_el != v)
        {
            if (!eliminate(p, v_el))
            {
                elimination_stack.clear();
                return false;
            }
        }
    }

    while (!elimination_stack.empty())
    {
        HistoryRecord rec = elimination_stack.back();
        elimination_stack.pop_back();
        Position p = rec.position;
        int v = rec.value;
        int r = p.row;
        int c = p.col;
        for (int house_type = 0; house_type < 3; ++house_type)
        {
            // house size
            int lr =    house_type == 0 ?  BOARD_SIZE
                   :    house_type == 1 ?  BOX_WIDTH
                   : /* house_type == 2 */ 1;
            int lc = BOARD_SIZE / lr;

            // house position
            int br = r / lr * lr;
            int bc = c / lc * lc;

            for (int dr = 0; dr < lr; ++dr)
            {
                for (int dc = 0; dc < lc; ++dc)
                {
                    int nr = br + dr;
                    int nc = bc + dc;
                    if (r != nr || c != nc)
                    {
                        if (!eliminate({nr, nc}, v))
                        {
                            elimination_stack.clear();
                            return false;
                        }
                    }
                }
            }
        }
    }

    return true;
}

bool SudokuSolver::eliminate(Position p, int v)
{
    if (!eliminated[p.row][p.col][v])
    {
        eliminated[p.row][p.col][v] = true;
        ++num_eliminated[p.row][p.col];
        history.push_back({p, v});
        if (num_eliminated[p.row][p.col] == BOARD_SIZE - 1)
        {
            for (int v_p = 0; v_p < BOARD_SIZE; ++v_p)
            {
                if (!eliminated[p.row][p.col][v_p])
                {
                    elimination_stack.push_back({p, v_p});
                }
            }
        }
        else if (num_eliminated[p.row][p.col] == BOARD_SIZE)
        {
            return false;
        }
    }
    return true;
}

CallStackRecord SudokuSolver::backtrack()
{
    CallStackRecord rec_c = call_stack.back();
    call_stack.pop_back();
    while (history.size() > rec_c.history_length)
    {
        HistoryRecord rec_h = history.back();
        history.pop_back();
        int r = rec_h.position.row;
        int c = rec_h.position.col;
        eliminated[r][c][rec_h.value] = false;
        --num_eliminated[r][c];
    }
    return rec_c;
}

bool SudokuSolver::solve(int const in_board[BOARD_SIZE][BOARD_SIZE], int out_board[BOARD_SIZE][BOARD_SIZE])
{
    SudokuSolver solver = in_board;

    if (!solver.solution_found)
    {
        return false;
    }

    for (int r = 0; r < BOARD_SIZE; ++r)
    {
        for (int c = 0; c < BOARD_SIZE; ++c)
        {
            for (int v = 0; v < BOARD_SIZE; ++v)
            {
                if (!solver.eliminated[r][c][v])
                {
                    out_board[r][c] = v + 1;
                }
            }
        }
    }

    return true;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "sysinv.h"
#include "argparser.h"
#include "version.h"
#include "smbios.h"

#define OUT_LIST	0x1
#define OUT_XML		0x2
#define OUT_JSON	0x3
#define OUT_WALK	0x4

int HotFixTest();

void print_usage(int ret);

int main(int argc, CHAR* argv[])
{
	FILE *out = stdout;
	PNODE root, agent, software, hardware, configuration, storage, network, node;
	DWORD format = OUT_LIST;
	DWORD i = 0;
	PARGLIST argList = parse_args(argc, argv);
	PARG arg;

	BOOL getSoftware = 1;
	BOOL getHardware = 1;
	BOOL getConfiguration = 1;

	for(i = 0; i < argList->count; i++) {
		arg = &argList->args[i];

		// Parse help request
		if(0 == strcmp("/?", arg->arg) || 0 == strcmp("-?", arg->arg)
			|| 0 == stricmp("/h", arg->arg) || 0 == strcmp("-h", arg->arg)
			|| 0 == strcmp("--help", arg->arg)) {
			print_usage(0);
		}

		// Parse file output argument
		else if(0 == stricmp("/f", arg->arg) || 0 == strcmp("-f", arg->arg)) {
			if(NULL == arg->val) {
				fprintf(stderr, "File name not specified.\n");
				exit(1);
			}

			if(NULL == (out = fopen(arg->val, "w"))) {
				fprintf(stderr, "Unable to open '%s' for writing.\n", arg->val);
				exit(1);
			}
		}

		// Parse output arguments
		else if(0 == stricmp("/o", arg->arg) || 0 == strcmp("-o", arg->arg)) {
			if(NULL == arg->val) {
				fprintf(stderr, "Output format not specified.\n");
				exit(1);
			}

			if(0 == stricmp("xml", arg->val))
				format = OUT_XML;

			else if(0 == stricmp("json", arg->val))
				format = OUT_JSON;

			else if (0 == stricmp("walk", arg->val))
				format = OUT_WALK;

			else if(0 == stricmp("list", arg->val))
				format = OUT_LIST;

			else {
				fprintf(stderr, "Unknown output type: '%s'\n", arg->val);
				exit(1);
			}
		}
	}

	free(argList);

	// Build info nodes
	root = GetSystemDetail();

	// Get agent info
	agent = GetAgentDetail();
	node_append_child(root, agent);

	if (getHardware) {
		hardware = node_append_new(root, L"Hardware", NFLG_PLACEHOLDER);

		// Virtualization info
		node = GetVirtualizationDetail();
		node_append_child(hardware, node);

		// SMBIOS info
		node = GetSmbiosDetail();
		node_append_child(hardware, node);

		// OEM String
		node = EnumOemStrings();
		node_append_child(hardware, node);

		// BIOS Info
		node = GetBiosDetail();
		node_append_child(hardware, node);

		// System Chassis
		node = EnumChassis();
		node_append_child(hardware, node);

		// Baseboards
		node = EnumBaseboards();
		node_append_child(hardware, node);

		// Memory
		node = EnumMemorySockets();
		node_append_child(hardware, node);

		// Processor Sockets
		node = EnumProcSockets();
		node_append_child(hardware, node);

		// Get CPU info
		node = EnumProcessors();
		node_append_child(hardware, node);

		// Get disks
		node = EnumDisks();
		node_append_child(hardware, node);
	}

	if (getSoftware) {
		software = node_append_new(root, L"Software", NFLG_PLACEHOLDER);

		// Get OS info
		node = GetOperatingSystemDetail();
		node_append_child(software, node);

		// Get Software packages
		node = EnumPackages();
		node_append_child(software, node);

		// Get hotfixes QFE
		node_append_child(software, EnumHotfixes());
	}

	if (getConfiguration) {
		configuration = node_append_new(root, L"Configuration", NFLG_PLACEHOLDER);
		storage = node_append_new(configuration, L"Storage", NFLG_PLACEHOLDER);
		network = node_append_new(configuration, L"Network", NFLG_PLACEHOLDER);

		// Get volume info
		node = EnumVolumes();
		node_append_child(storage, node);

		// Get network configuration
		node_append_child(network, EnumNetworkInterfaces());

		// Get network routes
		node_append_child(network, EnumNetworkRoutes());

		// Get Failover Cluster Node
		node = EnumClusterServices();
		if (NULL != node)
			node_append_child(configuration, node);
	}

	// Release residual handles
	ReleaseSmbiosData();

	// Add errors
	node = EnumErrorLog();
	if (NULL != node)
		node_append_child(root, node);

	// Print
	switch(format) {
	case OUT_XML:
		node_to_xml(root, out, 0);
		break;

	case OUT_JSON:
		node_to_json(root, out, 0);
		break;

	case OUT_WALK:
		node_to_walk(root, out, 0);
		break;

	case OUT_LIST:
		node_to_list(root, out, 0);
		break;
	}

	fclose(out);
	node_free(root, true);

	return 0;
}

void print_usage(int ret)
{
	printf("%s v%s\n%s %s\n\n%s\n\n",
		VER_PRODUCTNAME_STR, VER_PRODUCT_VERSION_STR,
		VER_COPYRIGHT_STR, VER_PRODUCT_COMPANY,
		VER_FILE_DESCRIPTION_STR);
	printf("%s [/F:filename] [/O:format]\n\n", VER_ORIGINAL_FILENAME_STR);
	printf("  /F          Write to file instead of printing to screen\n");
	printf("  /O          Change output format\n");
	printf("                LIST  Output data as snmp-walk style list\n");
	printf("                XML   Output data as XML tree\n");
	printf("                JSON  Output data as Javascript object\n");
	printf("                WALK  Output data as snmp-walk style list\n");
	printf("\n");
	exit(ret);
}<commit_msg>Prevented exception dialogs from being displayed<commit_after>#include "stdafx.h"
#include "sysinv.h"
#include "argparser.h"
#include "version.h"
#include "smbios.h"

#define OUT_LIST	0x1
#define OUT_XML		0x2
#define OUT_JSON	0x3
#define OUT_WALK	0x4

int HotFixTest();

void print_usage(int ret);

int main(int argc, CHAR* argv[])
{
	FILE *out = stdout;
	PNODE root, agent, software, hardware, configuration, storage, network, node;
	DWORD format = OUT_LIST;
	DWORD i = 0;
	PARGLIST argList = parse_args(argc, argv);
	PARG arg;

	BOOL getSoftware = 1;
	BOOL getHardware = 1;
	BOOL getConfiguration = 1;

	for(i = 0; i < argList->count; i++) {
		arg = &argList->args[i];

		// Parse help request
		if(0 == strcmp("/?", arg->arg) || 0 == strcmp("-?", arg->arg)
			|| 0 == stricmp("/h", arg->arg) || 0 == strcmp("-h", arg->arg)
			|| 0 == strcmp("--help", arg->arg)) {
			print_usage(0);
		}

		// Parse file output argument
		else if(0 == stricmp("/f", arg->arg) || 0 == strcmp("-f", arg->arg)) {
			if(NULL == arg->val) {
				fprintf(stderr, "File name not specified.\n");
				exit(1);
			}

			if(NULL == (out = fopen(arg->val, "w"))) {
				fprintf(stderr, "Unable to open '%s' for writing.\n", arg->val);
				exit(1);
			}
		}

		// Parse output arguments
		else if(0 == stricmp("/o", arg->arg) || 0 == strcmp("-o", arg->arg)) {
			if(NULL == arg->val) {
				fprintf(stderr, "Output format not specified.\n");
				exit(1);
			}

			if(0 == stricmp("xml", arg->val))
				format = OUT_XML;

			else if(0 == stricmp("json", arg->val))
				format = OUT_JSON;

			else if (0 == stricmp("walk", arg->val))
				format = OUT_WALK;

			else if(0 == stricmp("list", arg->val))
				format = OUT_LIST;

			else {
				fprintf(stderr, "Unknown output type: '%s'\n", arg->val);
				exit(1);
			}
		}
	}

	free(argList);

	// Configure error handling to prevent dialog boxes
	SetErrorMode(SEM_FAILCRITICALERRORS);

	// Build info nodes
	root = GetSystemDetail();

	// Get agent info
	agent = GetAgentDetail();
	node_append_child(root, agent);

	if (getHardware) {
		hardware = node_append_new(root, L"Hardware", NFLG_PLACEHOLDER);

		// Virtualization info
		node = GetVirtualizationDetail();
		node_append_child(hardware, node);

		// SMBIOS info
		node = GetSmbiosDetail();
		node_append_child(hardware, node);

		// OEM String
		node = EnumOemStrings();
		node_append_child(hardware, node);

		// BIOS Info
		node = GetBiosDetail();
		node_append_child(hardware, node);

		// System Chassis
		node = EnumChassis();
		node_append_child(hardware, node);

		// Baseboards
		node = EnumBaseboards();
		node_append_child(hardware, node);

		// Memory
		node = EnumMemorySockets();
		node_append_child(hardware, node);

		// Processor Sockets
		node = EnumProcSockets();
		node_append_child(hardware, node);

		// Get CPU info
		node = EnumProcessors();
		node_append_child(hardware, node);

		// Get disks
		node = EnumDisks();
		node_append_child(hardware, node);
	}

	if (getSoftware) {
		software = node_append_new(root, L"Software", NFLG_PLACEHOLDER);

		// Get OS info
		node = GetOperatingSystemDetail();
		node_append_child(software, node);

		// Get Software packages
		node = EnumPackages();
		node_append_child(software, node);

		// Get hotfixes QFE
		node_append_child(software, EnumHotfixes());
	}

	if (getConfiguration) {
		configuration = node_append_new(root, L"Configuration", NFLG_PLACEHOLDER);
		storage = node_append_new(configuration, L"Storage", NFLG_PLACEHOLDER);
		network = node_append_new(configuration, L"Network", NFLG_PLACEHOLDER);

		// Get volume info
		node = EnumVolumes();
		node_append_child(storage, node);

		// Get network configuration
		node_append_child(network, EnumNetworkInterfaces());

		// Get network routes
		node_append_child(network, EnumNetworkRoutes());

		// Get Failover Cluster Node
		node = EnumClusterServices();
		if (NULL != node)
			node_append_child(configuration, node);
	}

	// Release residual handles
	ReleaseSmbiosData();

	// Add errors
	node = EnumErrorLog();
	if (NULL != node)
		node_append_child(root, node);

	// Print
	switch(format) {
	case OUT_XML:
		node_to_xml(root, out, 0);
		break;

	case OUT_JSON:
		node_to_json(root, out, 0);
		break;

	case OUT_WALK:
		node_to_walk(root, out, 0);
		break;

	case OUT_LIST:
		node_to_list(root, out, 0);
		break;
	}

	fclose(out);
	node_free(root, true);

	return 0;
}

void print_usage(int ret)
{
	printf("%s v%s\n%s %s\n\n%s\n\n",
		VER_PRODUCTNAME_STR, VER_PRODUCT_VERSION_STR,
		VER_COPYRIGHT_STR, VER_PRODUCT_COMPANY,
		VER_FILE_DESCRIPTION_STR);
	printf("%s [/F:filename] [/O:format]\n\n", VER_ORIGINAL_FILENAME_STR);
	printf("  /F          Write to file instead of printing to screen\n");
	printf("  /O          Change output format\n");
	printf("                LIST  Output data as snmp-walk style list\n");
	printf("                XML   Output data as XML tree\n");
	printf("                JSON  Output data as Javascript object\n");
	printf("                WALK  Output data as snmp-walk style list\n");
	printf("\n");
	exit(ret);
}<|endoftext|>