<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: listviewbuilder.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: kz $ $Date: 2007-09-06 14:24:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_shell.hxx"

#ifdef _MSC_VER
#pragma warning (disable : 4786 4503)
#endif

//------------------------------------
// include
//------------------------------------

#ifndef LISTVIEWBUILDER_HXX_INCLUDED
#include "listviewbuilder.hxx"
#endif

#ifndef DOCUMENT_STATISTIC_HXX_INCLUDED
#include "document_statistic.hxx"
#endif

#ifndef UTILITIES_HXX_INCLUDED
#include "internal/utilities.hxx"
#endif

#ifndef CONFIG_HXX_INCLUDED
#include "internal/config.hxx"
#endif

#if defined _MSC_VER
#pragma warning(push, 1)
#endif
#include <commctrl.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif
#include <commctrl.h>
#include <tchar.h>

#ifndef RESOURCE_H_INCLUDED
#include "internal/resource.h"
#endif

//------------------------------------
//
//------------------------------------

list_view_builder_ptr create_list_view_builder(
    HWND hwnd_lv, const std::wstring& col1, const std::wstring& col2)
{
    if (is_windows_xp_or_above())
        return list_view_builder_ptr(new winxp_list_view_builder(hwnd_lv, col1, col2));
    else
        return list_view_builder_ptr(new list_view_builder(hwnd_lv, col1, col2));
}

//------------------------------------
//
//------------------------------------

list_view_builder::list_view_builder(
    HWND hwnd_list_view,
    const std::wstring& column1_title,
    const std::wstring& column2_title) :
    hwnd_list_view_(hwnd_list_view),
    row_index_(-1),
    column1_title_(column1_title),
    column2_title_(column2_title)
{
}

//------------------------------------
//
//------------------------------------

list_view_builder::~list_view_builder()
{
}

//------------------------------------
//
//------------------------------------

void list_view_builder::build(statistic_group_list_t& gl)
{
    setup_list_view();

    statistic_group_list_t::iterator group_iter     = gl.begin();
    statistic_group_list_t::iterator group_iter_end = gl.end();

    for (/**/; group_iter != group_iter_end; ++group_iter)
    {
        statistic_item_list_t::iterator item_iter     = group_iter->second.begin();
        statistic_item_list_t::iterator item_iter_end = group_iter->second.end();

        if (item_iter != item_iter_end)
            insert_group(group_iter->first);

        for (/**/; item_iter != item_iter_end; ++item_iter)
            insert_item(item_iter->title_, item_iter->value_, item_iter->editable_);
    }
}

//------------------------------------
//
//------------------------------------

void list_view_builder::setup_list_view()
{
    HIMAGELIST h_ils = ImageList_Create(16,15,ILC_MASK, 7, 0);
    HBITMAP    h_bmp = LoadBitmap(GetModuleHandle(MODULE_NAME), MAKEINTRESOURCE(IDB_PROPERTY_IMAGES));
    ImageList_AddMasked(h_ils, h_bmp, RGB(255, 0, 255));

    ListView_SetImageList(hwnd_list_view_, h_ils, LVSIL_SMALL);

    std::wstring header = GetResString(IDS_PROPERTY);

    LVCOLUMN lvc;
    lvc.mask = LVCF_FMT |
               LVCF_WIDTH |
                LVCF_TEXT |
               LVCF_SUBITEM;

    lvc.iSubItem = 0;
    lvc.pszText  = const_cast<wchar_t*>(header.c_str());
    lvc.cx       = 120;
    lvc.fmt      = LVCFMT_LEFT;

    ListView_InsertColumn(hwnd_list_view_, 0, &lvc);
    lvc.iSubItem = 1;
    header = GetResString(IDS_PROPERTY_VALUE);
    lvc.pszText = const_cast<wchar_t*>(header.c_str());
    ListView_InsertColumn(hwnd_list_view_, 1, &lvc);
}

//------------------------------------
//
//------------------------------------

void list_view_builder::insert_group(const std::wstring& /*title*/)
{
    insert_item(L"", L"", false);
}

//------------------------------------
//
//------------------------------------

void list_view_builder::insert_item(const std::wstring& title, const std::wstring& value, bool is_editable)
{
    LVITEM lvi;

    lvi.iItem      = ++row_index_;
    lvi.iSubItem   = 0;
    lvi.mask       = LVIF_TEXT;
    lvi.state      = 0;
    lvi.cchTextMax = title.size() + 1;
    lvi.stateMask  = 0;
    lvi.pszText    = const_cast<wchar_t*>(title.c_str());

    if (title.length() > 0)
    {
        lvi.mask |= LVIF_IMAGE;

        if (is_editable)
            lvi.iImage = 4;
        else
            lvi.iImage = 3;
    }

    ListView_InsertItem(hwnd_list_view_, &lvi);

    lvi.mask     = LVIF_TEXT;
    lvi.iSubItem = 1;
    lvi.pszText  = const_cast<wchar_t*>(value.c_str());

    ListView_SetItem(hwnd_list_view_, &lvi);
}

//------------------------------------
//
//------------------------------------

HWND list_view_builder::get_list_view() const
{
    return hwnd_list_view_;
}

//------------------------------------
//
//------------------------------------

winxp_list_view_builder::winxp_list_view_builder(
    HWND hwnd_list_view,
    const std::wstring& column1_title,
    const std::wstring& column2_title) :
    list_view_builder(hwnd_list_view, column1_title, column2_title),
    group_count_(-1),
    row_count_(0)
{
}

//------------------------------------
//
//------------------------------------

void winxp_list_view_builder::setup_list_view()
{
    list_view_builder::setup_list_view();

    ListView_EnableGroupView(get_list_view(), TRUE);
}

//------------------------------------
//
//------------------------------------

void winxp_list_view_builder::insert_group(const std::wstring& name)
{
    LVGROUP lvg;

    ZeroMemory(&lvg, sizeof(lvg));

    lvg.cbSize    = sizeof(lvg);
    lvg.mask      = LVGF_HEADER | LVGF_STATE | LVGF_GROUPID;
    lvg.pszHeader = const_cast<wchar_t*>(name.c_str());
    lvg.cchHeader = name.size() + 1;
    lvg.iGroupId  = ++group_count_;
    lvg.state     = LVGS_NORMAL;
    lvg.uAlign    = LVGA_HEADER_CENTER;

    ListView_InsertGroup(get_list_view(), row_count_++, &lvg);
}

//------------------------------------
//
//------------------------------------

void winxp_list_view_builder::insert_item(
    const std::wstring& title, const std::wstring& value, bool is_editable)
{
    LVITEM lvi;

    lvi.iItem      = ++row_index_;
    lvi.iSubItem   = 0;
    lvi.mask       = LVIF_TEXT | LVIF_GROUPID;
    lvi.state      = 0;
    lvi.stateMask  = 0;
    lvi.pszText    = const_cast<wchar_t*>(title.c_str());
    lvi.iGroupId   = group_count_;

    if (title.length() > 0)
    {
        lvi.mask |= LVIF_IMAGE;

        if (is_editable)
            lvi.iImage = 4;
        else
            lvi.iImage = 3;
    }

    ListView_InsertItem(get_list_view(), &lvi);

    lvi.mask     = LVIF_TEXT;
    lvi.iSubItem = 1;
    lvi.pszText  = const_cast<wchar_t*>(value.c_str());

    ListView_SetItem(get_list_view(), &lvi);

    row_count_++;
}
<commit_msg>INTEGRATION: CWS changefileheader (1.8.44); FILE MERGED 2008/04/01 12:41:15 thb 1.8.44.2: #i85898# Stripping all external header guards 2008/03/31 13:17:13 rt 1.8.44.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: listviewbuilder.cxx,v $
 * $Revision: 1.9 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_shell.hxx"

#ifdef _MSC_VER
#pragma warning (disable : 4786 4503)
#endif

//------------------------------------
// include
//------------------------------------
#include "listviewbuilder.hxx"
#include "document_statistic.hxx"
#include "internal/utilities.hxx"
#include "internal/config.hxx"

#if defined _MSC_VER
#pragma warning(push, 1)
#endif
#include <commctrl.h>
#if defined _MSC_VER
#pragma warning(pop)
#endif
#include <commctrl.h>
#include <tchar.h>
#include "internal/resource.h"

//------------------------------------
//
//------------------------------------

list_view_builder_ptr create_list_view_builder(
    HWND hwnd_lv, const std::wstring& col1, const std::wstring& col2)
{
    if (is_windows_xp_or_above())
        return list_view_builder_ptr(new winxp_list_view_builder(hwnd_lv, col1, col2));
    else
        return list_view_builder_ptr(new list_view_builder(hwnd_lv, col1, col2));
}

//------------------------------------
//
//------------------------------------

list_view_builder::list_view_builder(
    HWND hwnd_list_view,
    const std::wstring& column1_title,
    const std::wstring& column2_title) :
    hwnd_list_view_(hwnd_list_view),
    row_index_(-1),
    column1_title_(column1_title),
    column2_title_(column2_title)
{
}

//------------------------------------
//
//------------------------------------

list_view_builder::~list_view_builder()
{
}

//------------------------------------
//
//------------------------------------

void list_view_builder::build(statistic_group_list_t& gl)
{
    setup_list_view();

    statistic_group_list_t::iterator group_iter     = gl.begin();
    statistic_group_list_t::iterator group_iter_end = gl.end();

    for (/**/; group_iter != group_iter_end; ++group_iter)
    {
        statistic_item_list_t::iterator item_iter     = group_iter->second.begin();
        statistic_item_list_t::iterator item_iter_end = group_iter->second.end();

        if (item_iter != item_iter_end)
            insert_group(group_iter->first);

        for (/**/; item_iter != item_iter_end; ++item_iter)
            insert_item(item_iter->title_, item_iter->value_, item_iter->editable_);
    }
}

//------------------------------------
//
//------------------------------------

void list_view_builder::setup_list_view()
{
    HIMAGELIST h_ils = ImageList_Create(16,15,ILC_MASK, 7, 0);
    HBITMAP    h_bmp = LoadBitmap(GetModuleHandle(MODULE_NAME), MAKEINTRESOURCE(IDB_PROPERTY_IMAGES));
    ImageList_AddMasked(h_ils, h_bmp, RGB(255, 0, 255));

    ListView_SetImageList(hwnd_list_view_, h_ils, LVSIL_SMALL);

    std::wstring header = GetResString(IDS_PROPERTY);

    LVCOLUMN lvc;
    lvc.mask = LVCF_FMT |
               LVCF_WIDTH |
                LVCF_TEXT |
               LVCF_SUBITEM;

    lvc.iSubItem = 0;
    lvc.pszText  = const_cast<wchar_t*>(header.c_str());
    lvc.cx       = 120;
    lvc.fmt      = LVCFMT_LEFT;

    ListView_InsertColumn(hwnd_list_view_, 0, &lvc);
    lvc.iSubItem = 1;
    header = GetResString(IDS_PROPERTY_VALUE);
    lvc.pszText = const_cast<wchar_t*>(header.c_str());
    ListView_InsertColumn(hwnd_list_view_, 1, &lvc);
}

//------------------------------------
//
//------------------------------------

void list_view_builder::insert_group(const std::wstring& /*title*/)
{
    insert_item(L"", L"", false);
}

//------------------------------------
//
//------------------------------------

void list_view_builder::insert_item(const std::wstring& title, const std::wstring& value, bool is_editable)
{
    LVITEM lvi;

    lvi.iItem      = ++row_index_;
    lvi.iSubItem   = 0;
    lvi.mask       = LVIF_TEXT;
    lvi.state      = 0;
    lvi.cchTextMax = title.size() + 1;
    lvi.stateMask  = 0;
    lvi.pszText    = const_cast<wchar_t*>(title.c_str());

    if (title.length() > 0)
    {
        lvi.mask |= LVIF_IMAGE;

        if (is_editable)
            lvi.iImage = 4;
        else
            lvi.iImage = 3;
    }

    ListView_InsertItem(hwnd_list_view_, &lvi);

    lvi.mask     = LVIF_TEXT;
    lvi.iSubItem = 1;
    lvi.pszText  = const_cast<wchar_t*>(value.c_str());

    ListView_SetItem(hwnd_list_view_, &lvi);
}

//------------------------------------
//
//------------------------------------

HWND list_view_builder::get_list_view() const
{
    return hwnd_list_view_;
}

//------------------------------------
//
//------------------------------------

winxp_list_view_builder::winxp_list_view_builder(
    HWND hwnd_list_view,
    const std::wstring& column1_title,
    const std::wstring& column2_title) :
    list_view_builder(hwnd_list_view, column1_title, column2_title),
    group_count_(-1),
    row_count_(0)
{
}

//------------------------------------
//
//------------------------------------

void winxp_list_view_builder::setup_list_view()
{
    list_view_builder::setup_list_view();

    ListView_EnableGroupView(get_list_view(), TRUE);
}

//------------------------------------
//
//------------------------------------

void winxp_list_view_builder::insert_group(const std::wstring& name)
{
    LVGROUP lvg;

    ZeroMemory(&lvg, sizeof(lvg));

    lvg.cbSize    = sizeof(lvg);
    lvg.mask      = LVGF_HEADER | LVGF_STATE | LVGF_GROUPID;
    lvg.pszHeader = const_cast<wchar_t*>(name.c_str());
    lvg.cchHeader = name.size() + 1;
    lvg.iGroupId  = ++group_count_;
    lvg.state     = LVGS_NORMAL;
    lvg.uAlign    = LVGA_HEADER_CENTER;

    ListView_InsertGroup(get_list_view(), row_count_++, &lvg);
}

//------------------------------------
//
//------------------------------------

void winxp_list_view_builder::insert_item(
    const std::wstring& title, const std::wstring& value, bool is_editable)
{
    LVITEM lvi;

    lvi.iItem      = ++row_index_;
    lvi.iSubItem   = 0;
    lvi.mask       = LVIF_TEXT | LVIF_GROUPID;
    lvi.state      = 0;
    lvi.stateMask  = 0;
    lvi.pszText    = const_cast<wchar_t*>(title.c_str());
    lvi.iGroupId   = group_count_;

    if (title.length() > 0)
    {
        lvi.mask |= LVIF_IMAGE;

        if (is_editable)
            lvi.iImage = 4;
        else
            lvi.iImage = 3;
    }

    ListView_InsertItem(get_list_view(), &lvi);

    lvi.mask     = LVIF_TEXT;
    lvi.iSubItem = 1;
    lvi.pszText  = const_cast<wchar_t*>(value.c_str());

    ListView_SetItem(get_list_view(), &lvi);

    row_count_++;
}
<|endoftext|>


<commit_before>/*
    This file is part of KAddressBook.
    Copyright (c) 2002 Mike Pilone <mpilone@slac.com>

    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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 <qcheckbox.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qstring.h>
#include <qtoolbutton.h>
#include <qtooltip.h>

#include <kaccelmanager.h>
#include <kconfig.h>
#include <kcombobox.h>
#include <kdebug.h>
#include <kdialog.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <klocale.h>
#include <kmessagebox.h>

#include "emaileditwidget.h"

EmailEditWidget::EmailEditWidget( QWidget *parent, const char *name )
  : QWidget( parent, name )
{
  QGridLayout *topLayout = new QGridLayout( this, 2, 2, KDialog::marginHint(),
                                            KDialog::spacingHint() );

  QLabel *label = new QLabel( i18n( "Email:" ), this );
  topLayout->addWidget( label, 0, 0 );

  mEmailEdit = new KLineEdit( this );
  connect( mEmailEdit, SIGNAL( textChanged( const QString& ) ),
           SLOT( textChanged( const QString& ) ) );
  connect( mEmailEdit, SIGNAL( textChanged( const QString& ) ),
           SIGNAL( modified() ) );
  label->setBuddy( mEmailEdit );
  topLayout->addWidget( mEmailEdit, 0, 1 );

  QPushButton *editButton = new QPushButton( i18n( "Edit Email Addresses..." ), this);
  connect( editButton, SIGNAL( clicked() ), SLOT( edit() ) );
  topLayout->addMultiCellWidget( editButton, 1, 1, 0, 1 );

  topLayout->activate();
}

EmailEditWidget::~EmailEditWidget()
{
}

void EmailEditWidget::setEmails( const QStringList &list )
{
  mEmailList = list;

  bool blocked = mEmailEdit->signalsBlocked();
  mEmailEdit->blockSignals( true );
  if ( list.count() > 0 )
    mEmailEdit->setText( list[ 0 ] );
  else
    mEmailEdit->setText( "" );
  mEmailEdit->blockSignals( blocked );
}

QStringList EmailEditWidget::emails()
{
  if ( mEmailEdit->text().isEmpty() ) {
    if ( mEmailList.count() > 0 )
      mEmailList.remove( mEmailList.begin() );
  } else {
    if ( mEmailList.count() > 0 )
      mEmailList.remove( mEmailList.begin() );

    mEmailList.prepend( mEmailEdit->text() );
  }

  return mEmailList;
}

void EmailEditWidget::edit()
{
  EmailEditDialog dlg( mEmailList, this );

  if ( dlg.exec() ) {
    if ( dlg.changed() ) {
      mEmailList = dlg.emails();
      mEmailEdit->setText( mEmailList[ 0 ] );
      emit modified();
    }
  }
}

void EmailEditWidget::textChanged( const QString &text )
{
  if ( mEmailList.count() > 0 )
    mEmailList.remove( mEmailList.begin() );

  mEmailList.prepend( text );
}

EmailEditDialog::EmailEditDialog( const QStringList &list, QWidget *parent,
                                  const char *name )
  : KDialogBase( KDialogBase::Plain, i18n( "Edit Email Addresses" ),
                 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
                 parent, name, true )
{
  QWidget *page = plainPage();

  QGridLayout *topLayout = new QGridLayout( page, 4, 3, marginHint(),
                                            spacingHint() );

  QLabel *label = new QLabel( i18n( "Email address:" ), page );
  topLayout->addWidget( label, 0, 0 );

  mEmailEdit = new KLineEdit( page );
  label->setBuddy( mEmailEdit );
  topLayout->addWidget( mEmailEdit, 0, 1 );
  connect( mEmailEdit, SIGNAL( returnPressed() ), SLOT( add() ) );
  connect( mEmailEdit, SIGNAL( textChanged( const QString& ) ),
           SLOT( emailChanged() ) );

  mAddButton = new QPushButton( i18n( "Add" ), page );
  mAddButton->setEnabled( false );
  connect( mAddButton, SIGNAL( clicked() ), SLOT( add() ) );
  topLayout->addWidget( mAddButton, 0, 2 );

  mEmailListBox = new QListBox( page );

  // Make sure there is room for the scrollbar
  mEmailListBox->setMinimumHeight( mEmailListBox->sizeHint().height() + 30 );
  connect( mEmailListBox, SIGNAL( highlighted( int ) ),
           SLOT( selectionChanged( int ) ) );
  topLayout->addMultiCellWidget( mEmailListBox, 1, 3, 0, 1 );

  mEditButton = new QPushButton( i18n( "Change" ), page );
  connect( mEditButton, SIGNAL( clicked() ), SLOT( edit() ) );
  topLayout->addWidget( mEditButton, 1, 2 );

  mRemoveButton = new QPushButton( i18n( "Remove" ), page );
  connect( mRemoveButton, SIGNAL( clicked() ), SLOT( remove() ) );
  topLayout->addWidget( mRemoveButton, 2, 2 );

  mStandardButton = new QPushButton( i18n( "Set Standard" ), page );
  connect( mStandardButton, SIGNAL( clicked() ), SLOT( standard() ) );
  topLayout->addWidget( mStandardButton, 3, 2 );

  topLayout->activate();

  QStringList items = list;
  if ( items.remove( "" ) > 0 )
    mChanged = true;
  else
    mChanged = false;
  mEmailListBox->insertStringList( items );

  // set default state
  selectionChanged( -1 );

  KAcceleratorManager::manage( this );
}

EmailEditDialog::~EmailEditDialog()
{
}

QStringList EmailEditDialog::emails() const
{
  QStringList emails;

  for ( uint i = 0; i < mEmailListBox->count(); ++i )
    emails << mEmailListBox->text( i );

  return emails;
}

void EmailEditDialog::add()
{
  mEmailListBox->insertItem( mEmailEdit->text() );

  mEmailEdit->clear();
  mEmailEdit->setFocus();

  mChanged = true;
}

void EmailEditDialog::edit()
{
  mEmailEdit->setText( mEmailListBox->currentText() );
  mEmailEdit->setFocus();
}

void EmailEditDialog::remove()
{
  QString address = mEmailListBox->currentText();

  QString text = i18n( "<qt>Are you sure that you want to remove the email address %1?</qt>" ).arg( address );
  QString caption = i18n( "Confirm Remove" );

  if ( KMessageBox::questionYesNo( this, text, caption ) == KMessageBox::Yes ) {
    mEmailListBox->removeItem( mEmailListBox->currentItem() );
    mChanged = true;
  }
}

bool EmailEditDialog::changed() const
{
  return mChanged;
}

void EmailEditDialog::standard()
{
  QString text = mEmailListBox->currentText();
  mEmailListBox->removeItem( mEmailListBox->currentItem() );
  mEmailListBox->insertItem( text, 0 );
  mEmailListBox->setSelected( 0, true );

  mChanged = true;
}

void EmailEditDialog::selectionChanged( int index )
{
  bool value = ( index >= 0 ); // An item is selected

  mRemoveButton->setEnabled( value );
  mEditButton->setEnabled( value );
  mStandardButton->setEnabled( value );
}

void EmailEditDialog::emailChanged()
{
  mAddButton->setEnabled( !mEmailEdit->text().isEmpty() );
}

#include "emaileditwidget.moc"
<commit_msg>Add focus<commit_after>/*
    This file is part of KAddressBook.
    Copyright (c) 2002 Mike Pilone <mpilone@slac.com>

    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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 <qcheckbox.h>
#include <qlabel.h>
#include <qlayout.h>
#include <qpushbutton.h>
#include <qstring.h>
#include <qtoolbutton.h>
#include <qtooltip.h>

#include <kaccelmanager.h>
#include <kconfig.h>
#include <kcombobox.h>
#include <kdebug.h>
#include <kdialog.h>
#include <kiconloader.h>
#include <klineedit.h>
#include <klocale.h>
#include <kmessagebox.h>

#include "emaileditwidget.h"

EmailEditWidget::EmailEditWidget( QWidget *parent, const char *name )
  : QWidget( parent, name )
{
  QGridLayout *topLayout = new QGridLayout( this, 2, 2, KDialog::marginHint(),
                                            KDialog::spacingHint() );

  QLabel *label = new QLabel( i18n( "Email:" ), this );
  topLayout->addWidget( label, 0, 0 );

  mEmailEdit = new KLineEdit( this );
  connect( mEmailEdit, SIGNAL( textChanged( const QString& ) ),
           SLOT( textChanged( const QString& ) ) );
  connect( mEmailEdit, SIGNAL( textChanged( const QString& ) ),
           SIGNAL( modified() ) );
  label->setBuddy( mEmailEdit );
  topLayout->addWidget( mEmailEdit, 0, 1 );

  QPushButton *editButton = new QPushButton( i18n( "Edit Email Addresses..." ), this);
  connect( editButton, SIGNAL( clicked() ), SLOT( edit() ) );
  topLayout->addMultiCellWidget( editButton, 1, 1, 0, 1 );

  topLayout->activate();
}

EmailEditWidget::~EmailEditWidget()
{
}

void EmailEditWidget::setEmails( const QStringList &list )
{
  mEmailList = list;

  bool blocked = mEmailEdit->signalsBlocked();
  mEmailEdit->blockSignals( true );
  if ( list.count() > 0 )
    mEmailEdit->setText( list[ 0 ] );
  else
    mEmailEdit->setText( "" );
  mEmailEdit->blockSignals( blocked );
}

QStringList EmailEditWidget::emails()
{
  if ( mEmailEdit->text().isEmpty() ) {
    if ( mEmailList.count() > 0 )
      mEmailList.remove( mEmailList.begin() );
  } else {
    if ( mEmailList.count() > 0 )
      mEmailList.remove( mEmailList.begin() );

    mEmailList.prepend( mEmailEdit->text() );
  }

  return mEmailList;
}

void EmailEditWidget::edit()
{
  EmailEditDialog dlg( mEmailList, this );

  if ( dlg.exec() ) {
    if ( dlg.changed() ) {
      mEmailList = dlg.emails();
      mEmailEdit->setText( mEmailList[ 0 ] );
      emit modified();
    }
  }
}

void EmailEditWidget::textChanged( const QString &text )
{
  if ( mEmailList.count() > 0 )
    mEmailList.remove( mEmailList.begin() );

  mEmailList.prepend( text );
}

EmailEditDialog::EmailEditDialog( const QStringList &list, QWidget *parent,
                                  const char *name )
  : KDialogBase( KDialogBase::Plain, i18n( "Edit Email Addresses" ),
                 KDialogBase::Ok | KDialogBase::Cancel, KDialogBase::Ok,
                 parent, name, true )
{
  QWidget *page = plainPage();

  QGridLayout *topLayout = new QGridLayout( page, 4, 3, marginHint(),
                                            spacingHint() );

  QLabel *label = new QLabel( i18n( "Email address:" ), page );
  topLayout->addWidget( label, 0, 0 );

  mEmailEdit = new KLineEdit( page );
  label->setBuddy( mEmailEdit );
  topLayout->addWidget( mEmailEdit, 0, 1 );
  connect( mEmailEdit, SIGNAL( returnPressed() ), SLOT( add() ) );
  connect( mEmailEdit, SIGNAL( textChanged( const QString& ) ),
           SLOT( emailChanged() ) );

  mAddButton = new QPushButton( i18n( "Add" ), page );
  mAddButton->setEnabled( false );
  connect( mAddButton, SIGNAL( clicked() ), SLOT( add() ) );
  topLayout->addWidget( mAddButton, 0, 2 );

  mEmailListBox = new QListBox( page );

  // Make sure there is room for the scrollbar
  mEmailListBox->setMinimumHeight( mEmailListBox->sizeHint().height() + 30 );
  connect( mEmailListBox, SIGNAL( highlighted( int ) ),
           SLOT( selectionChanged( int ) ) );
  topLayout->addMultiCellWidget( mEmailListBox, 1, 3, 0, 1 );

  mEditButton = new QPushButton( i18n( "Change" ), page );
  connect( mEditButton, SIGNAL( clicked() ), SLOT( edit() ) );
  topLayout->addWidget( mEditButton, 1, 2 );

  mRemoveButton = new QPushButton( i18n( "Remove" ), page );
  connect( mRemoveButton, SIGNAL( clicked() ), SLOT( remove() ) );
  topLayout->addWidget( mRemoveButton, 2, 2 );

  mStandardButton = new QPushButton( i18n( "Set Standard" ), page );
  connect( mStandardButton, SIGNAL( clicked() ), SLOT( standard() ) );
  topLayout->addWidget( mStandardButton, 3, 2 );

  topLayout->activate();

  QStringList items = list;
  if ( items.remove( "" ) > 0 )
    mChanged = true;
  else
    mChanged = false;
  mEmailListBox->insertStringList( items );

  // set default state
  selectionChanged( -1 );
  mEmailEdit->setFocus();
  KAcceleratorManager::manage( this );
}

EmailEditDialog::~EmailEditDialog()
{
}

QStringList EmailEditDialog::emails() const
{
  QStringList emails;

  for ( uint i = 0; i < mEmailListBox->count(); ++i )
    emails << mEmailListBox->text( i );

  return emails;
}

void EmailEditDialog::add()
{
  mEmailListBox->insertItem( mEmailEdit->text() );

  mEmailEdit->clear();
  mEmailEdit->setFocus();

  mChanged = true;
}

void EmailEditDialog::edit()
{
  mEmailEdit->setText( mEmailListBox->currentText() );
  mEmailEdit->setFocus();
}

void EmailEditDialog::remove()
{
  QString address = mEmailListBox->currentText();

  QString text = i18n( "<qt>Are you sure that you want to remove the email address %1?</qt>" ).arg( address );
  QString caption = i18n( "Confirm Remove" );

  if ( KMessageBox::questionYesNo( this, text, caption ) == KMessageBox::Yes ) {
    mEmailListBox->removeItem( mEmailListBox->currentItem() );
    mChanged = true;
  }
}

bool EmailEditDialog::changed() const
{
  return mChanged;
}

void EmailEditDialog::standard()
{
  QString text = mEmailListBox->currentText();
  mEmailListBox->removeItem( mEmailListBox->currentItem() );
  mEmailListBox->insertItem( text, 0 );
  mEmailListBox->setSelected( 0, true );

  mChanged = true;
}

void EmailEditDialog::selectionChanged( int index )
{
  bool value = ( index >= 0 ); // An item is selected

  mRemoveButton->setEnabled( value );
  mEditButton->setEnabled( value );
  mStandardButton->setEnabled( value );
}

void EmailEditDialog::emailChanged()
{
  mAddButton->setEnabled( !mEmailEdit->text().isEmpty() );
}

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


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2015 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Modules/Legacy/String/PrintStringIntoString.h>
#include <stdio.h>

#include <Core/Datatypes/String.h>

#ifdef _WIN32
#define snprintf _snprintf
#endif

using namespace SCIRun::Modules::StringManip;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Core::Algorithms;

SCIRun::Core::Algorithms::AlgorithmParameterName PrintStringIntoString::FormatString("FormatString");

const ModuleLookupInfo PrintStringIntoString::staticInfo_("PrintStringIntoString", "String", "SCIRun");

PrintStringIntoString::PrintStringIntoString() : Module(staticInfo_)
{
  INITIALIZE_PORT(Format);
  INITIALIZE_PORT(Input);
  INITIALIZE_PORT(Output);
}

/// @class PrintStringIntoString
/// @brief This module does a sprintf with input strings into a new string.

void PrintStringIntoString::setStateDefaults()
{
  auto state = get_state();
  state->setValue(FormatString,std::string ("my string: %s"));
}

void
PrintStringIntoString::execute()
{
  std::string   format, output;

  StringHandle currentstring;
  int          inputport = 0;
  std::string  str;

  std::vector<char> buffer(256);
  bool    lastport = false;

  auto  stringH = getOptionalInput(Format);

  auto state = get_state();

  // check for port input and in none use gui input
  if (stringH && *stringH)
  {
    state -> setValue(FormatString, (*stringH) -> value());
  }
  format = state -> getValue(FormatString).toString();

  // Get the dynamic handles
  auto stringsH = getOptionalDynamicInputs(Input);

  if (needToExecute())
  {
    size_t i = 0;
    while(i < format.size())
    {
      if (format[i] == '%')
      {
        if (i == format.size()-1)
        {
          error("Improper format string '%' is last character");
          return;
      }

        if (format[i+1] == '%')
        {
            output += '%'; i += 2;
        }
        else
        {
          size_t j = i+1;
          // Just to name a few printing options
          while((j < format.size())&&(format[j] != 'd')&&(format[j] != 'e')&&(format[j] != 'g')&&(format[j] != 'c')
              &&(format[j] != 'i')&&(format[j] != 'E')&&(format[j] != 'x')&&(format[j] != 'X')&&(format[j] != 's')
              &&(format[j] != 'u')&&(format[j] != 'o')&&(format[j] != 'g')&&(format[j] != 'G')&&(format[j] != 'f')
              &&(format[j] != 'F')&&(format[j] != 'A')&&(format[j] != 'a')&&(format[j] != 's')&&(format[j] != 'C')&&(format[j] != 'p')&&(format[j] != 'P')) j++;

          if (j == format.size())
          {
              error("Improper format string '%..type' clause was incomplete");
              return;
          }

          std::string fstr = format.substr(i,j-i+1);

          {
            str = "";
            if (lastport == false)
            {
              if (inputport == stringsH.size())
              {
                lastport = true;
              }
              else
              {
                if (stringsH.size() == static_cast<size_t>(inputport))
                {
                  lastport = true;
                }
                else
                {
                  currentstring = stringsH[inputport]; inputport++;
                  if (currentstring)
                  {
                    str = currentstring->value();
                    std::cout<<" string " << inputport <<" = " << str <<std::endl;
                  }
                }
              }
            }
          }

          if ((format[j] == 's')||(format[j] == 'S')||(format[j] == 'c')||(format[j] == 'C'))
          {
            // We put the %s %S back in the string so it can be filled out lateron
            // By a different module

            if (j == i+1)
            {
              output += str;
            }
            else
            {
              // there is some modifier or so
              // This implementation is naive in assuming only
              // a buffer of 256 bytes. This needs to be altered one
              // day.
              snprintf(&(buffer[0]),256,fstr.c_str(),str.c_str());
              output += std::string(static_cast<char *>(&(buffer[0])));
            }
            i = j+1;

          }
          else if ((format[j] == 'd')||(format[j] == 'o')||(format[j] == 'i')||
                  (format[j] == 'u')||(format[j] == 'x')||(format[j] == 'X')||
                  (format[j] == 'e')||(format[j] == 'E')||(format[j] == 'f')||
                  (format[j] == 'F')||(format[j] == 'g')||(format[j] == 'G')||
                  (format[j] == 'a')||(format[j] == 'A')||(format[j] == 'p')||
                  (format[j] == 'P'))
          {
            output += fstr;
            i = j+1;
          }
        }
      }
      else if ( format[i] == '\\')
      {
        if (i < (format.size()-1))
        {
          switch (format[i+1])
          {
            case 'n': output += '\n'; break;
            case 'b': output += '\b'; break;
            case 't': output += '\t'; break;
            case 'r': output += '\r'; break;
            case '\\': output += '\\'; break;
            case '0': output += '\0'; break;
            case 'v': output += '\v'; break;
            default:
              error("unknown escape character");
              return;
          }
          i = i+2;
        }
      }
      else
      {
        output += format[i++];
      }
    }

    StringHandle handle(new String(output));
    sendOutput(Output, handle);
  }
}

<commit_msg>removed cout line that is not needed<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2015 Scientific Computing and Imaging Institute,
   University of Utah.

   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Modules/Legacy/String/PrintStringIntoString.h>
#include <stdio.h>

#include <Core/Datatypes/String.h>

#ifdef _WIN32
#define snprintf _snprintf
#endif

using namespace SCIRun::Modules::StringManip;
using namespace SCIRun::Core::Datatypes;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Core::Algorithms;

SCIRun::Core::Algorithms::AlgorithmParameterName PrintStringIntoString::FormatString("FormatString");

const ModuleLookupInfo PrintStringIntoString::staticInfo_("PrintStringIntoString", "String", "SCIRun");

PrintStringIntoString::PrintStringIntoString() : Module(staticInfo_)
{
  INITIALIZE_PORT(Format);
  INITIALIZE_PORT(Input);
  INITIALIZE_PORT(Output);
}

/// @class PrintStringIntoString
/// @brief This module does a sprintf with input strings into a new string.

void PrintStringIntoString::setStateDefaults()
{
  auto state = get_state();
  state->setValue(FormatString,std::string ("my string: %s"));
}

void
PrintStringIntoString::execute()
{
  std::string   format, output;

  StringHandle currentstring;
  int          inputport = 0;
  std::string  str;

  std::vector<char> buffer(256);
  bool    lastport = false;

  auto  stringH = getOptionalInput(Format);

  auto state = get_state();

  // check for port input and in none use gui input
  if (stringH && *stringH)
  {
    state -> setValue(FormatString, (*stringH) -> value());
  }
  format = state -> getValue(FormatString).toString();

  // Get the dynamic handles
  auto stringsH = getOptionalDynamicInputs(Input);

  if (needToExecute())
  {
    size_t i = 0;
    while(i < format.size())
    {
      if (format[i] == '%')
      {
        if (i == format.size()-1)
        {
          error("Improper format string '%' is last character");
          return;
      }

        if (format[i+1] == '%')
        {
            output += '%'; i += 2;
        }
        else
        {
          size_t j = i+1;
          // Just to name a few printing options
          while((j < format.size())&&(format[j] != 'd')&&(format[j] != 'e')&&(format[j] != 'g')&&(format[j] != 'c')
              &&(format[j] != 'i')&&(format[j] != 'E')&&(format[j] != 'x')&&(format[j] != 'X')&&(format[j] != 's')
              &&(format[j] != 'u')&&(format[j] != 'o')&&(format[j] != 'g')&&(format[j] != 'G')&&(format[j] != 'f')
              &&(format[j] != 'F')&&(format[j] != 'A')&&(format[j] != 'a')&&(format[j] != 's')&&(format[j] != 'C')&&(format[j] != 'p')&&(format[j] != 'P')) j++;

          if (j == format.size())
          {
              error("Improper format string '%..type' clause was incomplete");
              return;
          }

          std::string fstr = format.substr(i,j-i+1);

          {
            str = "";
            if (lastport == false)
            {
              if (inputport == stringsH.size())
              {
                lastport = true;
              }
              else
              {
                if (stringsH.size() == static_cast<size_t>(inputport))
                {
                  lastport = true;
                }
                else
                {
                  currentstring = stringsH[inputport]; inputport++;
                  if (currentstring)
                  {
                    str = currentstring->value();
                  }
                }
              }
            }
          }

          if ((format[j] == 's')||(format[j] == 'S')||(format[j] == 'c')||(format[j] == 'C'))
          {
            // We put the %s %S back in the string so it can be filled out lateron
            // By a different module

            if (j == i+1)
            {
              output += str;
            }
            else
            {
              // there is some modifier or so
              // This implementation is naive in assuming only
              // a buffer of 256 bytes. This needs to be altered one
              // day.
              snprintf(&(buffer[0]),256,fstr.c_str(),str.c_str());
              output += std::string(static_cast<char *>(&(buffer[0])));
            }
            i = j+1;

          }
          else if ((format[j] == 'd')||(format[j] == 'o')||(format[j] == 'i')||
                  (format[j] == 'u')||(format[j] == 'x')||(format[j] == 'X')||
                  (format[j] == 'e')||(format[j] == 'E')||(format[j] == 'f')||
                  (format[j] == 'F')||(format[j] == 'g')||(format[j] == 'G')||
                  (format[j] == 'a')||(format[j] == 'A')||(format[j] == 'p')||
                  (format[j] == 'P'))
          {
            output += fstr;
            i = j+1;
          }
        }
      }
      else if ( format[i] == '\\')
      {
        if (i < (format.size()-1))
        {
          switch (format[i+1])
          {
            case 'n': output += '\n'; break;
            case 'b': output += '\b'; break;
            case 't': output += '\t'; break;
            case 'r': output += '\r'; break;
            case '\\': output += '\\'; break;
            case '0': output += '\0'; break;
            case 'v': output += '\v'; break;
            default:
              error("unknown escape character");
              return;
          }
          i = i+2;
        }
      }
      else
      {
        output += format[i++];
      }
    }

    StringHandle handle(new String(output));
    sendOutput(Output, handle);
  }
}

<|endoftext|>


<commit_before>/*****************************************************************************
 * Copyright (C) 2013 Michael Krufky
 *
 * Author: Michael Krufky <mkrufky@linuxtv.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This library 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
 *
 *****************************************************************************/

#include "hlsinput.h"
#include "hlsfeed.h"

static void write_stdout(void *context, void *buffer, size_t size, size_t nmemb)
{
	fwrite(buffer, size, nmemb, stdout);
}

void hlsinput::write_feed(void *context, void *buffer, size_t size, size_t nmemb)
{
	static_cast<hlsinput*>(context)->feeder.push(size * nmemb, (const uint8_t*)buffer);
}

hlsinput::hlsinput(bool feed_stdout)
  : b_stdout(feed_stdout)
{
}

bool hlsinput::get(const char *url)
{
	if (b_stdout)
		hlsfeed hlsFeeder(url, write_stdout, this);
	else
		hlsfeed hlsFeeder(url, write_feed, this);

	return true;
}
<commit_msg>walk_hls: fix warning: unused parameter 'context' [-Wunused-parameter]<commit_after>/*****************************************************************************
 * Copyright (C) 2013 Michael Krufky
 *
 * Author: Michael Krufky <mkrufky@linuxtv.org>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * version 2 as published by the Free Software Foundation.
 *
 * This library 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
 *
 *****************************************************************************/

#include "hlsinput.h"
#include "hlsfeed.h"

static void write_stdout(void *context, void *buffer, size_t size, size_t nmemb)
{
	(void)context;
	fwrite(buffer, size, nmemb, stdout);
}

void hlsinput::write_feed(void *context, void *buffer, size_t size, size_t nmemb)
{
	static_cast<hlsinput*>(context)->feeder.push(size * nmemb, (const uint8_t*)buffer);
}

hlsinput::hlsinput(bool feed_stdout)
  : b_stdout(feed_stdout)
{
}

bool hlsinput::get(const char *url)
{
	if (b_stdout)
		hlsfeed hlsFeeder(url, write_stdout, this);
	else
		hlsfeed hlsFeeder(url, write_feed, this);

	return true;
}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2020)

#ifndef DUNE_GDT_SPACES_MAPPER_FINITE_VOLUME_SKELETON_HH
#define DUNE_GDT_SPACES_MAPPER_FINITE_VOLUME_SKELETON_HH

#include <dune/geometry/type.hh>

#include <dune/grid/common/mcmgmapper.hh>
#include <dune/grid/common/rangegenerators.hh>

#include <dune/xt/common/numeric_cast.hh>
#include <dune/xt/grid/type_traits.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/local/finite-elements/interfaces.hh>
#include <dune/gdt/local/finite-elements/lagrange.hh>

#include "interfaces.hh"
#include "finite-volume.hh"

namespace Dune {
namespace GDT {

template <class GV, size_t r = 1, size_t rC = 1>
class FiniteVolumeSkeletonMapper : public MapperInterface<GV>
{
  static_assert(r == 1, "The FiniteVolumeSkeletonMapper is not yet available for r > 1!");
  static_assert(rC == 1, "The FiniteVolumeSkeletonMapper is not yet available for rC > 1!");

  using ThisType = FiniteVolumeSkeletonMapper;
  using BaseType = MapperInterface<GV>;

public:
  using BaseType::d;
  using typename BaseType::D;

private:
  using Implementation = MultipleCodimMultipleGeomTypeMapper<GV>;
  using LocalFiniteElementFamily = LocalLagrangeFiniteElementFamily<D, d, double, r>;

public:
  using typename BaseType::ElementType;
  using typename BaseType::GridViewType;

  FiniteVolumeSkeletonMapper(const GridViewType& grd_vw)
    : grid_view_(grd_vw)
    , local_finite_elements_()
    , element_indices_(grid_view_)
    , mapper_(grid_view_, mcmgLayout(Codim<1>()))
    , element_to_global_indices_of_intersections_map_(element_indices_.size())
    , max_local_size_(0)
  {
    this->update_after_adapt();
  }

  FiniteVolumeSkeletonMapper(const ThisType&) = default;
  FiniteVolumeSkeletonMapper(ThisType&&) = default;

  FiniteVolumeSkeletonMapper& operator=(const ThisType&) = delete;
  FiniteVolumeSkeletonMapper& operator=(ThisType&&) = delete;

  const GridViewType& grid_view() const override final
  {
    return grid_view_;
  }

  const LocalFiniteElementCoefficientsInterface<D, d>&
  local_coefficients(const GeometryType& geometry_type) const override final
  {
    DUNE_THROW(Exceptions::mapper_error, "Not implemented yet for a skeleton mapper!");
    return local_finite_elements_.get(geometry_type, 0).coefficients();
  }

  size_t size() const override final
  {
    return mapper_.size();
  }

  size_t max_local_size() const override final
  {
    return max_local_size_;
  }

  size_t local_size(const ElementType& element) const override final
  {
    return element.subEntities(1u);
  }

  size_t global_index(const ElementType& element, const size_t local_index) const override final
  {
    const auto& global_indices_of_intersections =
        element_to_global_indices_of_intersections_map_[element_indices_.global_index(element, 0)];
    DUNE_THROW_IF(local_index >= global_indices_of_intersections.size(),
                  Exceptions::mapper_error,
                  "local_size(element) = " << global_indices_of_intersections.size()
                                           << "\n   local_index = " << local_index);
    return global_indices_of_intersections[local_index];
  }

  using BaseType::global_indices;

  void global_indices(const ElementType& element, DynamicVector<size_t>& indices) const override final
  {
    const auto& global_indices_of_intersections =
        element_to_global_indices_of_intersections_map_[element_indices_.global_index(element, 0)];
    const auto local_sz = global_indices_of_intersections.size();
    if (indices.size() < local_sz)
      indices.resize(local_sz);
    for (size_t ii = 0; ii < local_sz; ++ii)
      indices[ii] = global_indices_of_intersections[ii];
  } // ... global_indices(...)

  void update_after_adapt() override final
  {
    element_indices_.update_after_adapt();
    element_to_global_indices_of_intersections_map_.resize(element_indices_.size());
    mapper_.update();
    for (auto&& element : elements(grid_view_)) {
      const auto local_sz = this->local_size(element);
      max_local_size_ = std::max(max_local_size_, local_sz);
      auto& global_indices_of_intersections =
          element_to_global_indices_of_intersections_map_[element_indices_.global_index(element, 0)];
      global_indices_of_intersections.resize(local_sz);
      for (auto&& intersection : intersections(grid_view_, element)) {
        DUNE_THROW_IF(!intersection.conforming(),
                      Exceptions::mapper_error,
                      "Skeleton mapper not implemented for nonconforming intersections!");
        auto local_index = XT::Common::numeric_cast<size_t>(intersection.indexInInside());
        auto global_index = XT::Common::numeric_cast<size_t>(mapper_.index(element.template subEntity<1>(local_index)));
        global_indices_of_intersections[local_index] = global_index;
      }
    }
  } // ... update_after_adapt(...)

private:
  const GridViewType& grid_view_;
  LocalFiniteElementFamily local_finite_elements_;
  FiniteVolumeMapper<GV> element_indices_;
  Implementation mapper_;
  std::vector<DynamicVector<size_t>> element_to_global_indices_of_intersections_map_;
  size_t max_local_size_;
}; // class FiniteVolumeSkeletonMapper

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_MAPPER_FINITE_VOLUME_SKELETON_HH
<commit_msg>drop wrong int cast<commit_after>// This file is part of the dune-gdt project:
//   https://github.com/dune-community/dune-gdt
// Copyright 2010-2018 dune-gdt developers and contributors. All rights reserved.
// License: Dual licensed as BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)
//      or  GPL-2.0+ (http://opensource.org/licenses/gpl-license)
//          with "runtime exception" (http://www.dune-project.org/license.html)
// Authors:
//   Felix Schindler (2020)

#ifndef DUNE_GDT_SPACES_MAPPER_FINITE_VOLUME_SKELETON_HH
#define DUNE_GDT_SPACES_MAPPER_FINITE_VOLUME_SKELETON_HH

#include <dune/geometry/type.hh>

#include <dune/grid/common/mcmgmapper.hh>
#include <dune/grid/common/rangegenerators.hh>

#include <dune/xt/common/numeric_cast.hh>
#include <dune/xt/grid/type_traits.hh>

#include <dune/gdt/exceptions.hh>
#include <dune/gdt/local/finite-elements/interfaces.hh>
#include <dune/gdt/local/finite-elements/lagrange.hh>

#include "interfaces.hh"
#include "finite-volume.hh"

namespace Dune {
namespace GDT {

template <class GV, size_t r = 1, size_t rC = 1>
class FiniteVolumeSkeletonMapper : public MapperInterface<GV>
{
  static_assert(r == 1, "The FiniteVolumeSkeletonMapper is not yet available for r > 1!");
  static_assert(rC == 1, "The FiniteVolumeSkeletonMapper is not yet available for rC > 1!");

  using ThisType = FiniteVolumeSkeletonMapper;
  using BaseType = MapperInterface<GV>;

public:
  using BaseType::d;
  using typename BaseType::D;

private:
  using Implementation = MultipleCodimMultipleGeomTypeMapper<GV>;
  using LocalFiniteElementFamily = LocalLagrangeFiniteElementFamily<D, d, double, r>;

public:
  using typename BaseType::ElementType;
  using typename BaseType::GridViewType;

  FiniteVolumeSkeletonMapper(const GridViewType& grd_vw)
    : grid_view_(grd_vw)
    , local_finite_elements_()
    , element_indices_(grid_view_)
    , mapper_(grid_view_, mcmgLayout(Codim<1>()))
    , element_to_global_indices_of_intersections_map_(element_indices_.size())
    , max_local_size_(0)
  {
    this->update_after_adapt();
  }

  FiniteVolumeSkeletonMapper(const ThisType&) = default;
  FiniteVolumeSkeletonMapper(ThisType&&) = default;

  FiniteVolumeSkeletonMapper& operator=(const ThisType&) = delete;
  FiniteVolumeSkeletonMapper& operator=(ThisType&&) = delete;

  const GridViewType& grid_view() const override final
  {
    return grid_view_;
  }

  const LocalFiniteElementCoefficientsInterface<D, d>&
  local_coefficients(const GeometryType& geometry_type) const override final
  {
    DUNE_THROW(Exceptions::mapper_error, "Not implemented yet for a skeleton mapper!");
    return local_finite_elements_.get(geometry_type, 0).coefficients();
  }

  size_t size() const override final
  {
    return mapper_.size();
  }

  size_t max_local_size() const override final
  {
    return max_local_size_;
  }

  size_t local_size(const ElementType& element) const override final
  {
    return element.subEntities(1u);
  }

  size_t global_index(const ElementType& element, const size_t local_index) const override final
  {
    const auto& global_indices_of_intersections =
        element_to_global_indices_of_intersections_map_[element_indices_.global_index(element, 0)];
    DUNE_THROW_IF(local_index >= global_indices_of_intersections.size(),
                  Exceptions::mapper_error,
                  "local_size(element) = " << global_indices_of_intersections.size()
                                           << "\n   local_index = " << local_index);
    return global_indices_of_intersections[local_index];
  }

  using BaseType::global_indices;

  void global_indices(const ElementType& element, DynamicVector<size_t>& indices) const override final
  {
    const auto& global_indices_of_intersections =
        element_to_global_indices_of_intersections_map_[element_indices_.global_index(element, 0)];
    const auto local_sz = global_indices_of_intersections.size();
    if (indices.size() < local_sz)
      indices.resize(local_sz);
    for (size_t ii = 0; ii < local_sz; ++ii)
      indices[ii] = global_indices_of_intersections[ii];
  } // ... global_indices(...)

  void update_after_adapt() override final
  {
    element_indices_.update_after_adapt();
    element_to_global_indices_of_intersections_map_.resize(element_indices_.size());
    mapper_.update();
    for (auto&& element : elements(grid_view_)) {
      const auto local_sz = this->local_size(element);
      max_local_size_ = std::max(max_local_size_, local_sz);
      auto& global_indices_of_intersections =
          element_to_global_indices_of_intersections_map_[element_indices_.global_index(element, 0)];
      global_indices_of_intersections.resize(local_sz);
      for (auto&& intersection : intersections(grid_view_, element)) {
        DUNE_THROW_IF(!intersection.conforming(),
                      Exceptions::mapper_error,
                      "Skeleton mapper not implemented for nonconforming intersections!");
        auto local_index = intersection.indexInInside();
        auto global_index = XT::Common::numeric_cast<size_t>(mapper_.index(element.template subEntity<1>(local_index)));
        global_indices_of_intersections[local_index] = global_index;
      }
    }
  } // ... update_after_adapt(...)

private:
  const GridViewType& grid_view_;
  LocalFiniteElementFamily local_finite_elements_;
  FiniteVolumeMapper<GV> element_indices_;
  Implementation mapper_;
  std::vector<DynamicVector<size_t>> element_to_global_indices_of_intersections_map_;
  size_t max_local_size_;
}; // class FiniteVolumeSkeletonMapper

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_SPACES_MAPPER_FINITE_VOLUME_SKELETON_HH
<|endoftext|>


<commit_before>#include "FileAdapter.h"

namespace eparticle3d
{

void FileAdapter::Load(const std::string& filepath)
{
	Json::Value value;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, value);
	fin.close();

	name = value["name"].asString();
	package = value["package"].asString();

	count = value["count"].asInt();
	layer = value["layer"].asInt();
	emission_time = value["emission_time"].asInt() * 0.001f;

	if (!value["life"].isNull()) {
		life = value["life"]["center"].asInt();
		life_var = value["life"]["offset"].asInt();
	} else {
		int min = value["min_life"].asInt(),
			max = value["max_life"].asInt();
		life = (min + max) * 0.5f;
		life_var = (max - min) * 0.5f;
	}

	int min, max;
	min = value["min_hori"].asInt();
	max = value["max_hori"].asInt();
	hori = (min + max) * 0.5f * d2d::TRANS_DEG_TO_RAD;
	hori_var = (max - min) * 0.5f * d2d::TRANS_DEG_TO_RAD;

	min = value["min_vert"].asInt();
	max = value["max_vert"].asInt();
	vert = (min + max) * 0.5f * d2d::TRANS_DEG_TO_RAD;
	vert_var = (max - min) * 0.5f * d2d::TRANS_DEG_TO_RAD;

	if (!value["speed"].isNull()) {
		spd = value["speed"]["center"].asInt();
		spd_var = value["speed"]["offset"].asInt();
	} else {
		int min, max;
		min = value["min_spd"].asInt();
		max = value["max_spd"].asInt();
		spd = (min + max) * 0.5f;
		spd_var = (max - min) * 0.5f;
	}
	// todo
	spd *= 0.25f;
	spd_var *= 0.25f;

	if (!value["angular_speed"].isNull()) {
		angular_spd = value["angular_speed"]["center"].asInt();
		angular_spd_var = value["angular_speed"]["offset"].asInt();
	} else {
		int min, max;
		min = value["min_angular_spd"].asInt();
		max = value["max_angular_spd"].asInt();
		angular_spd = (min + max) * 0.5f;
		angular_spd_var = (max - min) * 0.5f;
	}

	dis_region = value["disturbance_radius"]["center"].asInt();
	dis_region_var = value["disturbance_radius"]["offset"].asInt();

	dis_spd = value["disturbance_spd"]["center"].asInt();
	dis_spd_var = value["disturbance_spd"]["offset"].asInt();

	gravity = value["gravity"].asInt();
	// todo
	gravity *= 0.3f;

	linear_acc = value["linear_acc"]["center"].asInt();
	linear_acc_var = value["linear_acc"]["offset"].asInt();

	inertia = value["inertia"].asInt();

	fadeout_time = value["fadeout_time"].asInt() * 0.001f;

	bounce = value["bounce"].asBool();
	additive_blend = value["additive_blend"].asBool();

	start_radius = value["start_radius"].asInt();
	is_start_radius_3d = value["start_radius_3d"].asBool();

	orient_to_movement = value["orient_to_movement"].asBool();
	orient_to_parent = value["orient_to_parent"].asBool();

	std::string dir = d2d::FilenameTools::getFileDir(filepath);
	int i = 0;
	Json::Value comp_val = value["components"][i++];
	while (!comp_val.isNull()) {
		LoadComponent(dir, comp_val);
		comp_val = value["components"][i++];
	}
}

void FileAdapter::LoadComponent(const std::string& dir, const Json::Value& comp_val)
{
	Component comp;

	comp.filepath = comp_val["filepath"].asString();
	comp.filepath = d2d::FilenameTools::getAbsolutePath(dir, comp.filepath);

	comp.bind_filepath = comp_val["bind ps filepath"].asString();
	comp.bind_filepath = d2d::FilenameTools::getAbsolutePath(dir, comp.bind_filepath);

	comp.name = comp_val["name"].asString();

	if (!comp_val["scale"].isNull()) {
		comp.scale_start = comp_val["scale"]["start"].asInt();
		comp.scale_end = comp_val["scale"]["start"].asInt();
	} else {
		comp.scale_start = comp_val["start_scale"].asInt();
		comp.scale_end = comp_val["end_scale"].asInt();
	}

	if (!comp_val["rotate"].isNull()) {
		comp.angle = comp_val["rotate"]["center"].asInt();
		comp.angle_var = comp_val["rotate"]["offset"].asInt();
	} else {
		int min = comp_val["rotate"]["min"].asInt(),
			max = comp_val["rotate"]["max"].asInt();
		comp.angle = (min + max) * 0.5f;
		comp.angle_var = (max - min) * 0.5f;
	}

	if (!comp_val["col_mul"].isNull()) {
		comp.col_mul.r = comp_val["col_mul"]["r"].asDouble();
		comp.col_mul.g = comp_val["col_mul"]["g"].asDouble();
		comp.col_mul.b = comp_val["col_mul"]["b"].asDouble();
	} else {
		comp.col_mul.r = comp.col_mul.g = comp.col_mul.b = 1;
	}

	if (!comp_val["col_add"].isNull()) {
		comp.col_add.r = comp_val["col_add"]["r"].asDouble();
		comp.col_add.g = comp_val["col_add"]["g"].asDouble();
		comp.col_add.b = comp_val["col_add"]["b"].asDouble();
	} else {
		comp.col_add.r = comp.col_add.g = comp.col_add.b = 0;
	}

	if (!comp_val["alpha"].isNull()) {
		comp.alpha_start = comp_val["alpha"]["start"].asInt();
		comp.alpha_end = comp_val["alpha"]["end"].asInt();
	} else {
		comp.alpha_start = comp.alpha_end = 100;
	}

	comp.start_z = comp_val["start_z"].asInt();

	components.push_back(comp);
}

}<commit_msg>[FIXED] particle symbol scale<commit_after>#include "FileAdapter.h"

namespace eparticle3d
{

void FileAdapter::Load(const std::string& filepath)
{
	Json::Value value;
	Json::Reader reader;
	std::locale::global(std::locale(""));
	std::ifstream fin(filepath.c_str());
	std::locale::global(std::locale("C"));
	reader.parse(fin, value);
	fin.close();

	name = value["name"].asString();
	package = value["package"].asString();

	count = value["count"].asInt();
	layer = value["layer"].asInt();
	emission_time = value["emission_time"].asInt() * 0.001f;

	if (!value["life"].isNull()) {
		life = value["life"]["center"].asInt();
		life_var = value["life"]["offset"].asInt();
	} else {
		int min = value["min_life"].asInt(),
			max = value["max_life"].asInt();
		life = (min + max) * 0.5f;
		life_var = (max - min) * 0.5f;
	}

	int min, max;
	min = value["min_hori"].asInt();
	max = value["max_hori"].asInt();
	hori = (min + max) * 0.5f * d2d::TRANS_DEG_TO_RAD;
	hori_var = (max - min) * 0.5f * d2d::TRANS_DEG_TO_RAD;

	min = value["min_vert"].asInt();
	max = value["max_vert"].asInt();
	vert = (min + max) * 0.5f * d2d::TRANS_DEG_TO_RAD;
	vert_var = (max - min) * 0.5f * d2d::TRANS_DEG_TO_RAD;

	if (!value["speed"].isNull()) {
		spd = value["speed"]["center"].asInt();
		spd_var = value["speed"]["offset"].asInt();
	} else {
		int min, max;
		min = value["min_spd"].asInt();
		max = value["max_spd"].asInt();
		spd = (min + max) * 0.5f;
		spd_var = (max - min) * 0.5f;
	}
	// todo
	spd *= 0.25f;
	spd_var *= 0.25f;

	if (!value["angular_speed"].isNull()) {
		angular_spd = value["angular_speed"]["center"].asInt();
		angular_spd_var = value["angular_speed"]["offset"].asInt();
	} else {
		int min, max;
		min = value["min_angular_spd"].asInt();
		max = value["max_angular_spd"].asInt();
		angular_spd = (min + max) * 0.5f;
		angular_spd_var = (max - min) * 0.5f;
	}

	dis_region = value["disturbance_radius"]["center"].asInt();
	dis_region_var = value["disturbance_radius"]["offset"].asInt();

	dis_spd = value["disturbance_spd"]["center"].asInt();
	dis_spd_var = value["disturbance_spd"]["offset"].asInt();

	gravity = value["gravity"].asInt();
	// todo
	gravity *= 0.3f;

	linear_acc = value["linear_acc"]["center"].asInt();
	linear_acc_var = value["linear_acc"]["offset"].asInt();

	inertia = value["inertia"].asInt();

	fadeout_time = value["fadeout_time"].asInt() * 0.001f;

	bounce = value["bounce"].asBool();
	additive_blend = value["additive_blend"].asBool();

	start_radius = value["start_radius"].asInt();
	is_start_radius_3d = value["start_radius_3d"].asBool();

	orient_to_movement = value["orient_to_movement"].asBool();
	orient_to_parent = value["orient_to_parent"].asBool();

	std::string dir = d2d::FilenameTools::getFileDir(filepath);
	int i = 0;
	Json::Value comp_val = value["components"][i++];
	while (!comp_val.isNull()) {
		LoadComponent(dir, comp_val);
		comp_val = value["components"][i++];
	}
}

void FileAdapter::LoadComponent(const std::string& dir, const Json::Value& comp_val)
{
	Component comp;

	comp.filepath = comp_val["filepath"].asString();
	comp.filepath = d2d::FilenameTools::getAbsolutePath(dir, comp.filepath);

	comp.bind_filepath = comp_val["bind ps filepath"].asString();
	comp.bind_filepath = d2d::FilenameTools::getAbsolutePath(dir, comp.bind_filepath);

	comp.name = comp_val["name"].asString();

	if (!comp_val["scale"].isNull()) {
		comp.scale_start = comp_val["scale"]["start"].asInt();
		comp.scale_end = comp_val["scale"]["end"].asInt();
	} else {
		comp.scale_start = comp_val["start_scale"].asInt();
		comp.scale_end = comp_val["end_scale"].asInt();
	}

	if (!comp_val["rotate"].isNull()) {
		comp.angle = comp_val["rotate"]["center"].asInt();
		comp.angle_var = comp_val["rotate"]["offset"].asInt();
	} else {
		int min = comp_val["rotate"]["min"].asInt(),
			max = comp_val["rotate"]["max"].asInt();
		comp.angle = (min + max) * 0.5f;
		comp.angle_var = (max - min) * 0.5f;
	}

	if (!comp_val["col_mul"].isNull()) {
		comp.col_mul.r = comp_val["col_mul"]["r"].asDouble();
		comp.col_mul.g = comp_val["col_mul"]["g"].asDouble();
		comp.col_mul.b = comp_val["col_mul"]["b"].asDouble();
	} else {
		comp.col_mul.r = comp.col_mul.g = comp.col_mul.b = 1;
	}

	if (!comp_val["col_add"].isNull()) {
		comp.col_add.r = comp_val["col_add"]["r"].asDouble();
		comp.col_add.g = comp_val["col_add"]["g"].asDouble();
		comp.col_add.b = comp_val["col_add"]["b"].asDouble();
	} else {
		comp.col_add.r = comp.col_add.g = comp.col_add.b = 0;
	}

	if (!comp_val["alpha"].isNull()) {
		comp.alpha_start = comp_val["alpha"]["start"].asInt();
		comp.alpha_end = comp_val["alpha"]["end"].asInt();
	} else {
		comp.alpha_start = comp.alpha_end = 100;
	}

	comp.start_z = comp_val["start_z"].asInt();

	components.push_back(comp);
}

}<|endoftext|>


<commit_before>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 "kudu/security/test/mini_kdc.h"

#include <csignal>
#include <cstdlib>

#include <map>
#include <memory>
#include <string>
#include <utility>

#include <boost/optional/optional.hpp>
#include <glog/logging.h>

#include "kudu/gutil/strings/strip.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/util/env.h"
#include "kudu/util/monotime.h"
#include "kudu/util/path_util.h"
#include "kudu/util/slice.h"
#include "kudu/util/stopwatch.h"
#include "kudu/util/subprocess.h"
#include "kudu/util/test_util.h"

using boost::none;
using std::map;
using std::string;
using std::unique_ptr;
using std::vector;
using strings::Substitute;

namespace kudu {

string MiniKdcOptions::ToString() const {
  return strings::Substitute("{ realm: $0, data_root: $1, port: $2, "
      "ticket_lifetime: $3, renew_lifetime: $4 }",
      realm, data_root, port, ticket_lifetime, renew_lifetime);
}

MiniKdc::MiniKdc()
    : MiniKdc(MiniKdcOptions()) {
}

MiniKdc::MiniKdc(MiniKdcOptions options)
    : options_(std::move(options)) {
  if (options_.realm.empty()) {
    options_.realm = "KRBTEST.COM";
  }
  if (options_.data_root.empty()) {
    options_.data_root = JoinPathSegments(GetTestDataDirectory(), "krb5kdc");
  }
  if (options_.ticket_lifetime.empty()) {
    options_.ticket_lifetime = "24h";
  }
  if (options_.renew_lifetime.empty()) {
    options_.renew_lifetime = "7d";
  }
}

MiniKdc::~MiniKdc() {
  if (kdc_process_) {
    WARN_NOT_OK(Stop(), "Unable to stop MiniKdc");
  }
}

map<string, string> MiniKdc::GetEnvVars() const {
  return {
    {"KRB5_CONFIG", JoinPathSegments(options_.data_root, "krb5.conf")},
    {"KRB5_KDC_PROFILE", JoinPathSegments(options_.data_root, "kdc.conf")},
    {"KRB5CCNAME", JoinPathSegments(options_.data_root, "krb5cc")},
    // Enable the workaround for MIT krb5 1.10 bugs from krb5_realm_override.cc.
    {"KUDU_ENABLE_KRB5_REALM_FIX", "yes"}
  };
}

vector<string> MiniKdc::MakeArgv(const vector<string>& in_argv) {
  vector<string> real_argv = { "env" };
  for (const auto& p : GetEnvVars()) {
    real_argv.push_back(Substitute("$0=$1", p.first, p.second));
  }
  for (const string& a : in_argv) {
    real_argv.push_back(a);
  }
  return real_argv;
}

namespace {
// Attempts to find the path to the specified Kerberos binary, storing it in 'path'.
Status GetBinaryPath(const string& binary, string* path) {
  static const vector<string> kCommonLocations = {
    "/usr/local/opt/krb5/sbin", // Homebrew
    "/usr/local/opt/krb5/bin", // Homebrew
    "/opt/local/sbin", // Macports
    "/opt/local/bin", // Macports
    "/usr/lib/mit/sbin", // SLES
    "/usr/sbin", // Linux
  };
  return FindExecutable(binary, kCommonLocations, path);
}
} // namespace

Status MiniKdc::Start() {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, "starting KDC");
  CHECK(!kdc_process_);
  VLOG(1) << "Starting Kerberos KDC: " << options_.ToString();

  if (!Env::Default()->FileExists(options_.data_root)) {
    VLOG(1) << "Creating KDC database and configuration files";
    RETURN_NOT_OK(Env::Default()->CreateDir(options_.data_root));

    RETURN_NOT_OK(CreateKdcConf());
    RETURN_NOT_OK(CreateKrb5Conf());

    // Create the KDC database using the kdb5_util tool.
    string kdb5_util_bin;
    RETURN_NOT_OK(GetBinaryPath("kdb5_util", &kdb5_util_bin));

    RETURN_NOT_OK(Subprocess::Call(MakeArgv({
        kdb5_util_bin, "create",
        "-s", // Stash the master password.
        "-P", "masterpw", // Set a password.
        "-W", // Use weak entropy (since we don't need real security).
    })));
  }

  // Start the Kerberos KDC.
  string krb5kdc_bin;
  RETURN_NOT_OK(GetBinaryPath("krb5kdc", &krb5kdc_bin));

  kdc_process_.reset(new Subprocess(
      MakeArgv({
      krb5kdc_bin,
      "-n", // Do not daemonize.
  })));

  RETURN_NOT_OK(kdc_process_->Start());

  const bool need_config_update = (options_.port == 0);
  // Wait for KDC to start listening on its ports and commencing operation
  // with a wildcard binding.
  RETURN_NOT_OK(WaitForUdpBind(kdc_process_->pid(), &options_.port,
                               /*addr=*/none, MonoDelta::FromSeconds(1)));

  if (need_config_update) {
    // If we asked for an ephemeral port, grab the actual ports and
    // rewrite the configuration so that clients can connect.
    RETURN_NOT_OK(CreateKrb5Conf());
    RETURN_NOT_OK(CreateKdcConf());
  }

  return Status::OK();
}

Status MiniKdc::Stop() {
  if (!kdc_process_) {
    return Status::OK();
  }
  VLOG(1) << "Stopping KDC";
  unique_ptr<Subprocess> proc(kdc_process_.release());
  RETURN_NOT_OK(proc->Kill(SIGKILL));
  RETURN_NOT_OK(proc->Wait());

  return Status::OK();
}

// Creates a kdc.conf file according to the provided options.
Status MiniKdc::CreateKdcConf() const {
  static const string kFileTemplate = R"(
[kdcdefaults]
kdc_ports = $2
kdc_tcp_ports = ""

[realms]
$1 = {
        acl_file = $0/kadm5.acl
        admin_keytab = $0/kadm5.keytab
        database_name = $0/principal
        key_stash_file = $0/.k5.$1
        max_renewable_life = 7d 0h 0m 0s
}
  )";
  string file_contents = strings::Substitute(kFileTemplate, options_.data_root,
                                             options_.realm, options_.port);
  return WriteStringToFile(Env::Default(), file_contents,
                           JoinPathSegments(options_.data_root, "kdc.conf"));
}

// Creates a krb5.conf file according to the provided options.
Status MiniKdc::CreateKrb5Conf() const {
  static const string kFileTemplate = R"(
[logging]
    kdc = FILE:/dev/stderr

[libdefaults]
    default_realm = $1
    dns_lookup_kdc = false
    dns_lookup_realm = false
    forwardable = true
    renew_lifetime = $2
    ticket_lifetime = $3

    # Disable aes256 since Java does not support it without JCE. Java is only
    # one of several minicluster consumers, but disabling aes256 doesn't
    # appreciably hurt Kudu code coverage, so we disable it universally.
    #
    # For more details, see:
    # https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/jgss-features.html
    default_tkt_enctypes = aes128-cts des3-cbc-sha1
    default_tgs_enctypes = aes128-cts des3-cbc-sha1
    permitted_enctypes = aes128-cts des3-cbc-sha1

    # In miniclusters, we start daemons on local loopback IPs that
    # have no reverse DNS entries. So, disable reverse DNS.
    rdns = false

    # The server side will start its GSSAPI server using the local FQDN.
    # However, in tests, we connect to it via a non-matching loopback IP.
    # This enables us to connect despite that mismatch.
    ignore_acceptor_hostname = true

[realms]
    $1 = {
        kdc = 127.0.0.1:$0
        # This super-arcane syntax can be found documented in various Hadoop
        # vendors' security guides and very briefly in the MIT krb5 docs.
        # Basically, this one says to map anyone coming in as foo@OTHERREALM.COM
        # and map them to a local user 'other-foo'
        auth_to_local = RULE:[1:other-$$1@$$0](.*@OTHERREALM.COM$$)s/@.*//
    }
  )";
  string file_contents = strings::Substitute(kFileTemplate, options_.port, options_.realm,
                                             options_.renew_lifetime, options_.ticket_lifetime);
  return WriteStringToFile(Env::Default(), file_contents,
                           JoinPathSegments(options_.data_root, "krb5.conf"));
}

Status MiniKdc::CreateUserPrincipal(const string& username) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("creating user principal $0", username));
  string kadmin;
  RETURN_NOT_OK(GetBinaryPath("kadmin.local", &kadmin));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("add_principal -pw $0 $0", username)})));
  return Status::OK();
}

Status MiniKdc::CreateServiceKeytab(const string& spn,
                                    string* path) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("creating service keytab for $0", spn));
  string kt_path = spn;
  StripString(&kt_path, "/", '_');
  kt_path = JoinPathSegments(options_.data_root, kt_path) + ".keytab";

  string kadmin;
  RETURN_NOT_OK(GetBinaryPath("kadmin.local", &kadmin));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("add_principal -randkey $0", spn)})));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("ktadd -k $0 $1", kt_path, spn)})));
  *path = kt_path;
  return Status::OK();
}

Status MiniKdc::RandomizePrincipalKey(const string& spn) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("randomizing key for $0", spn));
  string kadmin;
  RETURN_NOT_OK(GetBinaryPath("kadmin.local", &kadmin));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("change_password -randkey $0", spn)})));
  return Status::OK();
}

Status MiniKdc::CreateKeytabForExistingPrincipal(const string& spn) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("creating keytab for $0", spn));
  string kt_path = GetKeytabPathForPrincipal(spn);
  string kadmin;
  RETURN_NOT_OK(GetBinaryPath("kadmin.local", &kadmin));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("xst -norandkey -k $0 $1", kt_path, spn)})));
  return Status::OK();
}

string MiniKdc::GetKeytabPathForPrincipal(const string& spn) const {
  string kt_path = spn;
  StripString(&kt_path, "/", '_');
  return JoinPathSegments(options_.data_root, kt_path) + ".keytab";
}

Status MiniKdc::Kinit(const string& username) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("kinit for $0", username));
  string kinit;
  RETURN_NOT_OK(GetBinaryPath("kinit", &kinit));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({ kinit, username }), username));
  return Status::OK();
}

Status MiniKdc::Kdestroy() {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, "kdestroy");
  string kdestroy;
  RETURN_NOT_OK(GetBinaryPath("kdestroy", &kdestroy));
  return Subprocess::Call(MakeArgv({ kdestroy, "-A" }));
}

Status MiniKdc::Klist(string* output) {
  string klist;
  RETURN_NOT_OK(GetBinaryPath("klist", &klist));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({ klist, "-A" }), "", output));
  return Status::OK();
}

Status MiniKdc::KlistKeytab(const string& keytab_path, string* output) {
  string klist;
  RETURN_NOT_OK(GetBinaryPath("klist", &klist));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({ klist, "-k", keytab_path }), "", output));
  return Status::OK();
}

Status MiniKdc::SetKrb5Environment() const {
  if (!kdc_process_) {
    return Status::IllegalState("KDC not started");
  }
  for (const auto& p : GetEnvVars()) {
    CHECK_ERR(setenv(p.first.c_str(), p.second.c_str(), 1 /*overwrite*/));
  }

  return Status::OK();
}

} // namespace kudu
<commit_msg>[mini_kdc] MiniKdc::Kinit() atomically replaces ccache<commit_after>// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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 "kudu/security/test/mini_kdc.h"

#include <csignal>
#include <cstdlib>

#include <map>
#include <memory>
#include <string>
#include <utility>

#include <boost/optional/optional.hpp>
#include <glog/logging.h>

#include "kudu/gutil/map-util.h"
#include "kudu/gutil/strings/strip.h"
#include "kudu/gutil/strings/substitute.h"
#include "kudu/util/env.h"
#include "kudu/util/monotime.h"
#include "kudu/util/path_util.h"
#include "kudu/util/scoped_cleanup.h"
#include "kudu/util/slice.h"
#include "kudu/util/stopwatch.h"
#include "kudu/util/subprocess.h"
#include "kudu/util/test_util.h"

using boost::none;
using std::map;
using std::string;
using std::unique_ptr;
using std::vector;
using strings::Substitute;

namespace kudu {

string MiniKdcOptions::ToString() const {
  return strings::Substitute("{ realm: $0, data_root: $1, port: $2, "
      "ticket_lifetime: $3, renew_lifetime: $4 }",
      realm, data_root, port, ticket_lifetime, renew_lifetime);
}

MiniKdc::MiniKdc()
    : MiniKdc(MiniKdcOptions()) {
}

MiniKdc::MiniKdc(MiniKdcOptions options)
    : options_(std::move(options)) {
  if (options_.realm.empty()) {
    options_.realm = "KRBTEST.COM";
  }
  if (options_.data_root.empty()) {
    options_.data_root = JoinPathSegments(GetTestDataDirectory(), "krb5kdc");
  }
  if (options_.ticket_lifetime.empty()) {
    options_.ticket_lifetime = "24h";
  }
  if (options_.renew_lifetime.empty()) {
    options_.renew_lifetime = "7d";
  }
}

MiniKdc::~MiniKdc() {
  if (kdc_process_) {
    WARN_NOT_OK(Stop(), "Unable to stop MiniKdc");
  }
}

map<string, string> MiniKdc::GetEnvVars() const {
  return {
    {"KRB5_CONFIG", JoinPathSegments(options_.data_root, "krb5.conf")},
    {"KRB5_KDC_PROFILE", JoinPathSegments(options_.data_root, "kdc.conf")},
    {"KRB5CCNAME", JoinPathSegments(options_.data_root, "krb5cc")},
    // Enable the workaround for MIT krb5 1.10 bugs from krb5_realm_override.cc.
    {"KUDU_ENABLE_KRB5_REALM_FIX", "yes"}
  };
}

vector<string> MiniKdc::MakeArgv(const vector<string>& in_argv) {
  vector<string> real_argv = { "env" };
  for (const auto& p : GetEnvVars()) {
    real_argv.push_back(Substitute("$0=$1", p.first, p.second));
  }
  for (const string& a : in_argv) {
    real_argv.push_back(a);
  }
  return real_argv;
}

namespace {
// Attempts to find the path to the specified Kerberos binary, storing it in 'path'.
Status GetBinaryPath(const string& binary, string* path) {
  static const vector<string> kCommonLocations = {
    "/usr/local/opt/krb5/sbin", // Homebrew
    "/usr/local/opt/krb5/bin", // Homebrew
    "/opt/local/sbin", // Macports
    "/opt/local/bin", // Macports
    "/usr/lib/mit/sbin", // SLES
    "/usr/sbin", // Linux
  };
  return FindExecutable(binary, kCommonLocations, path);
}
} // namespace

Status MiniKdc::Start() {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, "starting KDC");
  CHECK(!kdc_process_);
  VLOG(1) << "Starting Kerberos KDC: " << options_.ToString();

  if (!Env::Default()->FileExists(options_.data_root)) {
    VLOG(1) << "Creating KDC database and configuration files";
    RETURN_NOT_OK(Env::Default()->CreateDir(options_.data_root));

    RETURN_NOT_OK(CreateKdcConf());
    RETURN_NOT_OK(CreateKrb5Conf());

    // Create the KDC database using the kdb5_util tool.
    string kdb5_util_bin;
    RETURN_NOT_OK(GetBinaryPath("kdb5_util", &kdb5_util_bin));

    RETURN_NOT_OK(Subprocess::Call(MakeArgv({
        kdb5_util_bin, "create",
        "-s", // Stash the master password.
        "-P", "masterpw", // Set a password.
        "-W", // Use weak entropy (since we don't need real security).
    })));
  }

  // Start the Kerberos KDC.
  string krb5kdc_bin;
  RETURN_NOT_OK(GetBinaryPath("krb5kdc", &krb5kdc_bin));

  kdc_process_.reset(new Subprocess(
      MakeArgv({
      krb5kdc_bin,
      "-n", // Do not daemonize.
  })));

  RETURN_NOT_OK(kdc_process_->Start());

  const bool need_config_update = (options_.port == 0);
  // Wait for KDC to start listening on its ports and commencing operation
  // with a wildcard binding.
  RETURN_NOT_OK(WaitForUdpBind(kdc_process_->pid(), &options_.port,
                               /*addr=*/none, MonoDelta::FromSeconds(1)));

  if (need_config_update) {
    // If we asked for an ephemeral port, grab the actual ports and
    // rewrite the configuration so that clients can connect.
    RETURN_NOT_OK(CreateKrb5Conf());
    RETURN_NOT_OK(CreateKdcConf());
  }

  return Status::OK();
}

Status MiniKdc::Stop() {
  if (!kdc_process_) {
    return Status::OK();
  }
  VLOG(1) << "Stopping KDC";
  unique_ptr<Subprocess> proc(kdc_process_.release());
  RETURN_NOT_OK(proc->Kill(SIGKILL));
  RETURN_NOT_OK(proc->Wait());

  return Status::OK();
}

// Creates a kdc.conf file according to the provided options.
Status MiniKdc::CreateKdcConf() const {
  static const string kFileTemplate = R"(
[kdcdefaults]
kdc_ports = $2
kdc_tcp_ports = ""

[realms]
$1 = {
        acl_file = $0/kadm5.acl
        admin_keytab = $0/kadm5.keytab
        database_name = $0/principal
        key_stash_file = $0/.k5.$1
        max_renewable_life = 7d 0h 0m 0s
}
  )";
  string file_contents = strings::Substitute(kFileTemplate, options_.data_root,
                                             options_.realm, options_.port);
  return WriteStringToFile(Env::Default(), file_contents,
                           JoinPathSegments(options_.data_root, "kdc.conf"));
}

// Creates a krb5.conf file according to the provided options.
Status MiniKdc::CreateKrb5Conf() const {
  static const string kFileTemplate = R"(
[logging]
    kdc = FILE:/dev/stderr

[libdefaults]
    default_realm = $1
    dns_lookup_kdc = false
    dns_lookup_realm = false
    forwardable = true
    renew_lifetime = $2
    ticket_lifetime = $3

    # Disable aes256 since Java does not support it without JCE. Java is only
    # one of several minicluster consumers, but disabling aes256 doesn't
    # appreciably hurt Kudu code coverage, so we disable it universally.
    #
    # For more details, see:
    # https://docs.oracle.com/javase/8/docs/technotes/guides/security/jgss/jgss-features.html
    default_tkt_enctypes = aes128-cts des3-cbc-sha1
    default_tgs_enctypes = aes128-cts des3-cbc-sha1
    permitted_enctypes = aes128-cts des3-cbc-sha1

    # In miniclusters, we start daemons on local loopback IPs that
    # have no reverse DNS entries. So, disable reverse DNS.
    rdns = false

    # The server side will start its GSSAPI server using the local FQDN.
    # However, in tests, we connect to it via a non-matching loopback IP.
    # This enables us to connect despite that mismatch.
    ignore_acceptor_hostname = true

[realms]
    $1 = {
        kdc = 127.0.0.1:$0
        # This super-arcane syntax can be found documented in various Hadoop
        # vendors' security guides and very briefly in the MIT krb5 docs.
        # Basically, this one says to map anyone coming in as foo@OTHERREALM.COM
        # and map them to a local user 'other-foo'
        auth_to_local = RULE:[1:other-$$1@$$0](.*@OTHERREALM.COM$$)s/@.*//
    }
  )";
  string file_contents = strings::Substitute(kFileTemplate, options_.port, options_.realm,
                                             options_.renew_lifetime, options_.ticket_lifetime);
  return WriteStringToFile(Env::Default(), file_contents,
                           JoinPathSegments(options_.data_root, "krb5.conf"));
}

Status MiniKdc::CreateUserPrincipal(const string& username) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("creating user principal $0", username));
  string kadmin;
  RETURN_NOT_OK(GetBinaryPath("kadmin.local", &kadmin));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("add_principal -pw $0 $0", username)})));
  return Status::OK();
}

Status MiniKdc::CreateServiceKeytab(const string& spn,
                                    string* path) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("creating service keytab for $0", spn));
  string kt_path = spn;
  StripString(&kt_path, "/", '_');
  kt_path = JoinPathSegments(options_.data_root, kt_path) + ".keytab";

  string kadmin;
  RETURN_NOT_OK(GetBinaryPath("kadmin.local", &kadmin));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("add_principal -randkey $0", spn)})));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("ktadd -k $0 $1", kt_path, spn)})));
  *path = kt_path;
  return Status::OK();
}

Status MiniKdc::RandomizePrincipalKey(const string& spn) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("randomizing key for $0", spn));
  string kadmin;
  RETURN_NOT_OK(GetBinaryPath("kadmin.local", &kadmin));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("change_password -randkey $0", spn)})));
  return Status::OK();
}

Status MiniKdc::CreateKeytabForExistingPrincipal(const string& spn) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("creating keytab for $0", spn));
  string kt_path = GetKeytabPathForPrincipal(spn);
  string kadmin;
  RETURN_NOT_OK(GetBinaryPath("kadmin.local", &kadmin));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({
          kadmin, "-q", Substitute("xst -norandkey -k $0 $1", kt_path, spn)})));
  return Status::OK();
}

string MiniKdc::GetKeytabPathForPrincipal(const string& spn) const {
  string kt_path = spn;
  StripString(&kt_path, "/", '_');
  return JoinPathSegments(options_.data_root, kt_path) + ".keytab";
}

Status MiniKdc::Kinit(const string& username) {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, Substitute("kinit for $0", username));
  string kinit;
  RETURN_NOT_OK(GetBinaryPath("kinit", &kinit));
  unique_ptr<WritableFile> tmp_cc_file;
  string tmp_cc_path;
  const auto tmp_template = Substitute("kinit-temp-$0.XXXXXX", username);
  RETURN_NOT_OK_PREPEND(Env::Default()->NewTempWritableFile(
      WritableFileOptions(),
      JoinPathSegments(options_.data_root, tmp_template),
      &tmp_cc_path, &tmp_cc_file),
      "could not create temporary file");
  auto delete_tmp_cc = MakeScopedCleanup([&]() {
    WARN_NOT_OK(Env::Default()->DeleteFile(tmp_cc_path),
                "could not delete file " + tmp_cc_path);
  });
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({ kinit, "-c", tmp_cc_path, username }), username));
  const auto env_vars_map = GetEnvVars();
  const auto& ccache_path = FindOrDie(env_vars_map, "KRB5CCNAME");
  RETURN_NOT_OK_PREPEND(Env::Default()->RenameFile(tmp_cc_path, ccache_path),
                        "could not move new file into place");
  delete_tmp_cc.cancel();
  return Status::OK();
}

Status MiniKdc::Kdestroy() {
  SCOPED_LOG_SLOW_EXECUTION(WARNING, 100, "kdestroy");
  string kdestroy;
  RETURN_NOT_OK(GetBinaryPath("kdestroy", &kdestroy));
  return Subprocess::Call(MakeArgv({ kdestroy, "-A" }));
}

Status MiniKdc::Klist(string* output) {
  string klist;
  RETURN_NOT_OK(GetBinaryPath("klist", &klist));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({ klist, "-A" }), "", output));
  return Status::OK();
}

Status MiniKdc::KlistKeytab(const string& keytab_path, string* output) {
  string klist;
  RETURN_NOT_OK(GetBinaryPath("klist", &klist));
  RETURN_NOT_OK(Subprocess::Call(MakeArgv({ klist, "-k", keytab_path }), "", output));
  return Status::OK();
}

Status MiniKdc::SetKrb5Environment() const {
  if (!kdc_process_) {
    return Status::IllegalState("KDC not started");
  }
  for (const auto& p : GetEnvVars()) {
    CHECK_ERR(setenv(p.first.c_str(), p.second.c_str(), 1 /*overwrite*/));
  }

  return Status::OK();
}

} // namespace kudu
<|endoftext|>