<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_hcode_image_build.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef __HCODE_IMG_BUILD_H_
#define __HCODE_IMG_BUILD_H_

#include <stdint.h>

///
/// @file   p9_hcode_image_build.H
/// @brief  describes HWP interface that builds the STOP image.
///
/// *HWP HWP Owner:      Greg Still <stillgs@us.ibm.com>
/// *HWP FW Owner:       Prem S Jha <premjha2@in.ibm.com>
/// *HWP Team:           PM
/// *HWP Level:          2
/// *HWP Consumed by:    Hostboot:Phyp
//

//--------------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------------
#include <fapi2.H>

extern "C"
{
    typedef  const fapi2::Target< fapi2::TARGET_TYPE_PROC_CHIP > CONST_FAPI2_PROC;

    /**
     * @brief   phases of system associated for hcode image build.
     */
    enum SysPhase_t
    {
        PHASE_NA        =   0,
        PHASE_IPL       =   1,
        PHASE_REBUILD   =   2,
        PHASE_END       =   3,
    };

    /**
     * @brief   constants used for hcode image build.
     */
    enum
    {
        HW_IMG_RING_SIZE   =  1024 * 1024,
    };

    /**
     * @brief image types to be handled by the hcode image build HWP.
     * @note  structure below summarizes all the components that needs to be
     *        included during STOP image build. Setting a field to 1 means that
     *        it needs to be part of STOP image in HOMER. It can be used to
     *        build partial STOP image in HOMER.
     */
    struct ImageType_t
    {
        uint32_t selfRestoreBuild: 1;       // for self restore code inclusion
        uint32_t cmeHcodeBuild: 1;           // for cme hcode inclusion
        uint32_t cmeCommonRingBuild: 1;      // for core ring inclusion
        uint32_t cmeCoreSpecificRingBuild: 1; // for core specific scan ring inclusion
        uint32_t sgpeHcodeBuild: 1;          // for sgpe inclusion
        uint32_t sgpeCommonRingBuild: 1;     // for sgpe common scan ring inclusion
        uint32_t sgpeCacheSpecificRingBuild: 1; // for cache specific ring inclusion
        uint32_t pgpeImageBuild: 1;      // pgpe platform inclusion in image build
        uint32_t pgpePstateParmBlockBuild: 1; //pgpe P-State Parameter Block Build
        uint32_t reserve: 23;

        ImageType_t( )
        {
            memset( this , 0, sizeof (*this) );
            this->selfRestoreBuild |= 0x01;
            this->cmeHcodeBuild |= 0x01;
            this->cmeCommonRingBuild |= 0x01;
            this->cmeCoreSpecificRingBuild |= 0x01;
            this->sgpeHcodeBuild |= 0x01;
            this->sgpeCommonRingBuild |= 0x01;
            this->sgpeCacheSpecificRingBuild |= 0x01;
            this->pgpeImageBuild |= 0x01;
            this->pgpePstateParmBlockBuild |= 0x01;
        }

        bool isBuildValid()
        {
            bool buildValid = false;

            if ( ( this->selfRestoreBuild ) ||
                 ( this->cmeHcodeBuild ) ||
                 ( this->cmeCommonRingBuild ) ||
                 ( this->cmeCoreSpecificRingBuild ) ||
                 ( this->sgpeHcodeBuild ) ||
                 ( this->sgpeCommonRingBuild ) ||
                 ( this->sgpeCacheSpecificRingBuild ) ||
                 ( this->pgpeImageBuild ) ||
                 ( this->pgpePstateParmBlockBuild ) )
            {
                buildValid = true;
            }

            return buildValid;
        }
    };

    typedef fapi2::ReturnCode( *p9_hcode_image_build_FP_t )
    ( CONST_FAPI2_PROC& i_procTgt,
      void* const i_pImageIn,
      void* o_pImageOut,
      SysPhase_t i_phase,
      ImageType_t i_imgType,
      void* i_pBuf );

    /**
    * @brief   builds a STOP image using a refrence image as input.
    * @param   i_procTgt    fapi2 target for processor chip.
    * @param   i_pImageIn   points to memory mapped refrence image in PNOR.
    * @param   o_pImageOut  pointer to the beginning of the HOMER image buffer.
    * @param   i_phase      phase of the system i.e. IPL or Hypervisor/rebuild mode.
    * @param   i_pBuf       buffer of size >= HW_IMG_RING_SIZE for handling ring.
    * @note    needs attribute ATTR_EC
    */
    fapi2::ReturnCode p9_hcode_image_build( CONST_FAPI2_PROC& i_procTgt,
                                            void* const i_pImageIn,
                                            void* o_pImageOut,
                                            SysPhase_t i_phase,
                                            ImageType_t i_imgType,
                                            void*     i_pBuf );
} // extern C
#endif //__HCODE_IMG_BUILD_H_
<commit_msg>PM:Revised hcode image build.<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/pm/p9_hcode_image_build.H $ */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
#ifndef __HCODE_IMG_BUILD_H_
#define __HCODE_IMG_BUILD_H_

#include <stdint.h>

///
/// @file   p9_hcode_image_build.H
/// @brief  describes HWP interface that builds the STOP image.
///
/// *HWP HWP Owner:      Greg Still <stillgs@us.ibm.com>
/// *HWP FW Owner:       Prem S Jha <premjha2@in.ibm.com>
/// *HWP Team:           PM
/// *HWP Level:          2
/// *HWP Consumed by:    Hostboot:Phyp
//

//--------------------------------------------------------------------------
// Includes
//--------------------------------------------------------------------------
#include <fapi2.H>

extern "C"
{
    typedef  const fapi2::Target< fapi2::TARGET_TYPE_PROC_CHIP > CONST_FAPI2_PROC;

    /**
     * @brief   phases of system associated for hcode image build.
     */
    enum SysPhase_t
    {
        PHASE_NA        =   0,
        PHASE_IPL       =   1,
        PHASE_REBUILD   =   2,
        PHASE_END       =   3,
    };

    /**
     * @brief   constants used for hcode image build.
     */
    enum
    {
        HW_IMG_RING_SIZE   =  1024 * 1024,
    };

    /**
     * @brief image types to be handled by the hcode image build HWP.
     * @note  structure below summarizes all the components that needs to be
     *        included during STOP image build. Setting a field to 1 means that
     *        it needs to be part of STOP image in HOMER. It can be used to
     *        build partial STOP image in HOMER.
     */
    struct ImageType_t
    {
        uint32_t selfRestoreBuild: 1;       // for self restore code inclusion
        uint32_t cmeHcodeBuild: 1;           // for cme hcode inclusion
        uint32_t cmeCommonRingBuild: 1;      // for core ring inclusion
        uint32_t cmeCoreSpecificRingBuild: 1; // for core specific scan ring inclusion
        uint32_t sgpeHcodeBuild: 1;          // for sgpe inclusion
        uint32_t sgpeCommonRingBuild: 1;     // for sgpe common scan ring inclusion
        uint32_t sgpeCacheSpecificRingBuild: 1; // for cache specific ring inclusion
        uint32_t pgpeImageBuild: 1;      // pgpe platform inclusion in image build
        uint32_t pgpePstateParmBlockBuild: 1; //pgpe P-State Parameter Block Build
        uint32_t reserve: 23;

        ImageType_t( )
        {
            memset( this , 0, sizeof (*this) );
            this->selfRestoreBuild |= 0x01;
            this->cmeHcodeBuild |= 0x01;
            this->cmeCommonRingBuild |= 0x01;
            this->cmeCoreSpecificRingBuild |= 0x01;
            this->sgpeHcodeBuild |= 0x01;
            this->sgpeCommonRingBuild |= 0x01;
            this->sgpeCacheSpecificRingBuild |= 0x01;
            this->pgpeImageBuild |= 0x01;
            this->pgpePstateParmBlockBuild |= 0x01;
        }

        bool isBuildValid()
        {
            bool buildValid = false;

            if ( ( this->selfRestoreBuild ) ||
                 ( this->cmeHcodeBuild ) ||
                 ( this->cmeCommonRingBuild ) ||
                 ( this->cmeCoreSpecificRingBuild ) ||
                 ( this->sgpeHcodeBuild ) ||
                 ( this->sgpeCommonRingBuild ) ||
                 ( this->sgpeCacheSpecificRingBuild ) ||
                 ( this->pgpeImageBuild ) ||
                 ( this->pgpePstateParmBlockBuild ) )
            {
                buildValid = true;
            }

            return buildValid;
        }
    };

    typedef fapi2::ReturnCode( *p9_hcode_image_build_FP_t )
    ( CONST_FAPI2_PROC& i_procTgt,
      void* const   i_pImageIn,
      void*         i_pHomerImage,
      void* const   i_pRingOverride,
      SysPhase_t    i_phase,
      ImageType_t i_imgType,
      void*  const    i_pBuf1,
      const  uint32_t i_sizeBuf1,
      void*  const    i_pBuf2,
      const  uint32_t  i_sizeBuf2 );

    /**
    * @brief   builds a STOP image using a refrence image as input.
    * @param   i_procTgt        fapi2 target for processor chip.
    * @param   i_pImageIn       points to memory mapped refrence image in PNOR.
    * @param   i_pHomerImage    pointer to the beginning of the HOMER image buffer.
    * @param   i_pRingOverride  pointer to the location of override ring. NULL means override not available.
    * @param   i_phase          phase of the system i.e. IPL or Hypervisor/rebuild mode.
    * @param   i_imgType        image type to be built.
    * @param   i_pBuf1          pointer to a work buffer1.
    * @param   i_sizeBuf1       size of work buffer1. Minimum size expected HW_IMG_RING_SIZE.
    * @param   i_pBuf2          pointer to a work buffer2. Minimum size expected HW_IMG_RING_SIZE.
    * @param   i_sizeBuf2       size of work buffer2
    * @note    needs attribute ATTR_EC
    */
    fapi2::ReturnCode p9_hcode_image_build( CONST_FAPI2_PROC& i_procTgt,
                                            void* const     i_pImageIn,
                                            void*           i_pHomerImage,
                                            void* const     i_pRingOverride,
                                            SysPhase_t      i_phase,
                                            ImageType_t     i_imgType,
                                            void*  const    i_pBuf1,
                                            const  uint32_t i_sizeBuf1,
                                            void* const    i_pBuf2,
                                            const uint32_t  i_sizeBuf2
                                          );
} // extern C
#endif //__HCODE_IMG_BUILD_H_
<|endoftext|>


<commit_before>/*
 *  scope_INDI.cpp
 *  PHD Guiding
 *
 *  Copyright (c) 2017 Oleg Kutkov
 *  All rights reserved.
 *
 *  This source code is distributed under the following "BSD" license
 *  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 Craig Stark, Stark Labs 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 HOLDER 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.
 *
 */

#include "phd.h"
#include "config_CRAO.h"

#include <stdio.h>

#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>

#ifdef GUIDE_ZTSH

ScopeZTSH::ScopeZTSH()
	: ctx (NULL)
{
}

ScopeZTSH::~ScopeZTSH()
{

}

bool ScopeZTSH::Connect(void)
{
	bool connect_failed = false;

	wxString device = pConfig->Profile.GetString("/crao/serial", _T(""));

	if (device.IsEmpty()) {
		wxMessageBox(_("Please select serial device in the mount configuration dialog"), _("Error"), wxOK | wxICON_ERROR);
		return true;
	}

#if defined (__linux__)
	device = wxString("/dev/") + device;
#elif defined (__WINDOWS__)
	device = wxString("\\\\.\\") + device;
#endif

	wxString parity = pConfig->Profile.GetString("/crao/parity", "n");
	parity = parity.Capitalize();

	const char *parity_c = parity.mb_str();

	int baud = pConfig->Profile.GetInt("/crao/baud", 9600);
	int dbits = pConfig->Profile.GetInt("/crao/dbits", 8);
	int sbits = pConfig->Profile.GetInt("/crao/sbits", 1);

	const char *device_c = device.mb_str();

	ctx = modbus_new_rtu(device_c, baud, parity_c[0], dbits, sbits);

	if (!ctx) {
		wxMessageBox(_("Failed to initialize modbus using current serial configuration"), _("Error"), wxOK | wxICON_ERROR);
		return true;
	}

	int mbid = pConfig->Profile.GetInt("/crao/mbid", 10);

	if (modbus_set_slave(ctx, mbid) != 0) {
		wxMessageBox(_("Failed to set selected modbus slave id"), _("Error"), wxOK | wxICON_ERROR);
		modbus_free(ctx);
		return true;
	}

	if (modbus_connect(ctx) != 0) {
		wxMessageBox(wxString("Modbus connection failed with error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
		modbus_free(ctx);
		return true;
	}

	uint16_t hw_answ;

	if (modbus_read_registers(ctx, 70, 1, &hw_answ) == -1) {
		wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
		modbus_close(ctx);
		modbus_free(ctx);
		return true;
	}

	if (hw_answ != 100) {
		wxMessageBox(wxString("Failed to communicate with the Mount hardware, strange answer from device"), _("Error"), wxOK | wxICON_ERROR);
		modbus_close(ctx);
		modbus_free(ctx);
		return true;
	}

	Scope::Connect();

	return connect_failed;
}

bool ScopeZTSH::Disconnect(void)
{
	modbus_close(ctx);
	modbus_free(ctx);

	ctx = NULL;

	Scope::Disconnect();

	return true;
}

bool ScopeZTSH::HasSetupDialog(void) const
{
    return true;
}

void ScopeZTSH::EnumerateSerialDevices(std::vector<wxString>& devices)
{
#if defined (__linux__)

	DIR *ttydir;
	struct dirent *devdir;

	const char *topdir = "/sys/class/tty/";

	ttydir = opendir(topdir);

	if (!ttydir) {
		return;
	}

	while ((devdir = readdir(ttydir)) != NULL) {
		char path[100];
		int len = snprintf(path, sizeof(path) - 1, "%s/%s/device", topdir, devdir->d_name);
		path[len] = 0;

		DIR *ttydevdir = opendir(path);

		if (!ttydevdir) {
			continue;
		}

		devices.push_back(devdir->d_name);
	}

	closedir(ttydir);

#elif defined (__WINDOWS__)
	/// TODO: implement me!
#endif
}

void ScopeZTSH::SetupDialog()
{
    CraoConfig *craoDlg = new CraoConfig(wxGetActiveWindow(), ctx);

	if (ctx) {
		craoDlg->SetConnectedState();
	}

	craoDlg->curr_device = pConfig->Profile.GetString("/crao/serial", _T(""));
	craoDlg->curr_baud = pConfig->Profile.GetInt("/crao/baud", 9600);
	craoDlg->curr_dbits = pConfig->Profile.GetInt("/crao/dbits", 8);
	craoDlg->curr_sbits = pConfig->Profile.GetInt("/crao/sbits", 1);
	craoDlg->curr_parity = pConfig->Profile.GetString("/crao/parity", "none");
	craoDlg->curr_mbid = pConfig->Profile.GetInt("/crao/mbid", 10);

	EnumerateSerialDevices(craoDlg->tty_devices);

    // initialize with actual values
	craoDlg->LoadSettings();

    if (craoDlg->ShowModal() == wxID_OK) {
		// if OK save the values to the current profile
		craoDlg->SaveSettings();

		pConfig->Profile.SetString("/crao/serial", craoDlg->curr_device);
		pConfig->Profile.SetInt("/crao/baud", craoDlg->curr_baud);
		pConfig->Profile.SetInt("/crao/dbits", craoDlg->curr_dbits);
		pConfig->Profile.SetInt("/crao/sbits", craoDlg->curr_sbits);
		pConfig->Profile.SetString("/crao/parity", craoDlg->curr_parity);
		pConfig->Profile.SetInt("/crao/mbid", craoDlg->curr_mbid);
    }

	craoDlg->Destroy();

	delete craoDlg;
}

bool ScopeZTSH::CanPulseGuide()
{
	return true;
}

static wxString PulseGuideFailedAlertEnabledKey()
{
	// we want the key to be under "/Confirm" so ConfirmDialog::ResetAllDontAskAgain() resets it, but we also want the setting to be per-profile
	return wxString::Format("/Confirm/%d/PulseGuideFailedAlertEnabled", pConfig->GetCurrentProfileId());
}

static void SuppressPulseGuideFailedAlert(long)
{
	pConfig->Global.SetBoolean(PulseGuideFailedAlertEnabledKey(), false);
}

Mount::MOVE_RESULT ScopeZTSH::Guide(GUIDE_DIRECTION direction, int duration)
{
    switch (direction) {
        case EAST:
			if (modbus_write_register(ctx, 11, duration) == -1)  {
				wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
				pFrame->SuppressableAlert(PulseGuideFailedAlertEnabledKey(), _("PulseGuide command to mount has failed - guiding is likely to be ineffective."), SuppressPulseGuideFailedAlert, 0);

				return MOVE_STOP_GUIDING;
			}

			printf("Pulse RA+ for %i\n", duration);
            break;

        case WEST:
			if (modbus_write_register(ctx, 12, duration) == -1) {
				wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
				pFrame->SuppressableAlert(PulseGuideFailedAlertEnabledKey(), _("PulseGuide command to mount has failed - guiding is likely to be ineffective."), SuppressPulseGuideFailedAlert, 0);

				return MOVE_STOP_GUIDING;
			}

			printf("Pulse RA- for %i\n", duration);
            break;

        case NORTH:
			if (modbus_write_register(ctx, 21, duration) == -1) {
				wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
				pFrame->SuppressableAlert(PulseGuideFailedAlertEnabledKey(), _("PulseGuide command to mount has failed - guiding is likely to be ineffective."), SuppressPulseGuideFailedAlert, 0);

				return MOVE_ERROR;
			}

			printf("Pulse DEC+ for %i\n", duration);
            break;

        case SOUTH:
			if (modbus_write_register(ctx, 22, duration) == -1) {
				wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
				pFrame->SuppressableAlert(PulseGuideFailedAlertEnabledKey(), _("PulseGuide command to mount has failed - guiding is likely to be ineffective."), SuppressPulseGuideFailedAlert, 0);

				return MOVE_ERROR;
			}

			printf("Pulse DEC- for %i\n", duration);
            break;

        case NONE:
		    printf("error ScopeZTSH::Guide NONE\n");
            break;
    }

    wxMilliSleep(duration);

	return MOVE_OK;
}

#endif

<commit_msg>win support<commit_after>/*
 *  scope_INDI.cpp
 *  PHD Guiding
 *
 *  Copyright (c) 2017 Oleg Kutkov
 *  All rights reserved.
 *
 *  This source code is distributed under the following "BSD" license
 *  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 Craig Stark, Stark Labs 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 HOLDER 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.
 *
 */

#include "phd.h"
#include "config_CRAO.h"
#include "serialport.h"

#include <stdio.h>

#if defined (__linux__)
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#endif

#ifdef GUIDE_ZTSH

ScopeZTSH::ScopeZTSH()
	: ctx (NULL)
{
}

ScopeZTSH::~ScopeZTSH()
{

}

bool ScopeZTSH::Connect(void)
{
	bool connect_failed = false;

	wxString device = pConfig->Profile.GetString("/crao/serial", _T(""));

	if (device.IsEmpty()) {
		wxMessageBox(_("Please select serial device in the mount configuration dialog"), _("Error"), wxOK | wxICON_ERROR);
		return true;
	}

#if defined (__linux__)
	device = wxString("/dev/") + device;
#elif defined (__WINDOWS__)
	device = wxString("\\\\.\\") + device;
#endif

	wxString parity = pConfig->Profile.GetString("/crao/parity", "n");
	parity = parity.Capitalize();

	const char *parity_c = parity.mb_str();

	int baud = pConfig->Profile.GetInt("/crao/baud", 9600);
	int dbits = pConfig->Profile.GetInt("/crao/dbits", 8);
	int sbits = pConfig->Profile.GetInt("/crao/sbits", 1);

	const char *device_c = device.mb_str();

	ctx = modbus_new_rtu(device_c, baud, parity_c[0], dbits, sbits);

	if (!ctx) {
		wxMessageBox(_("Failed to initialize modbus using current serial configuration"), _("Error"), wxOK | wxICON_ERROR);
		return true;
	}

	int mbid = pConfig->Profile.GetInt("/crao/mbid", 10);

	if (modbus_set_slave(ctx, mbid) != 0) {
		wxMessageBox(_("Failed to set selected modbus slave id"), _("Error"), wxOK | wxICON_ERROR);
		modbus_free(ctx);
		return true;
	}

	if (modbus_connect(ctx) != 0) {
		wxMessageBox(wxString("Modbus connection failed with error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
		modbus_free(ctx);
		return true;
	}

	uint16_t hw_answ;

	if (modbus_read_registers(ctx, 70, 1, &hw_answ) == -1) {
		wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
		modbus_close(ctx);
		modbus_free(ctx);
		return true;
	}

	if (hw_answ != 100) {
		wxMessageBox(wxString("Failed to communicate with the Mount hardware, strange answer from device"), _("Error"), wxOK | wxICON_ERROR);
		modbus_close(ctx);
		modbus_free(ctx);
		return true;
	}

	Scope::Connect();

	return connect_failed;
}

bool ScopeZTSH::Disconnect(void)
{
	modbus_close(ctx);
	modbus_free(ctx);

	ctx = NULL;

	Scope::Disconnect();

	return true;
}

bool ScopeZTSH::HasSetupDialog(void) const
{
    return true;
}

void ScopeZTSH::EnumerateSerialDevices(std::vector<wxString>& devices)
{
#if defined (__linux__)

	DIR *ttydir;
	struct dirent *devdir;

	const char *topdir = "/sys/class/tty/";

	ttydir = opendir(topdir);

	if (!ttydir) {
		return;
	}

	while ((devdir = readdir(ttydir)) != NULL) {
		char path[100];
		int len = snprintf(path, sizeof(path) - 1, "%s/%s/device", topdir, devdir->d_name);
		path[len] = 0;

		DIR *ttydevdir = opendir(path);

		if (!ttydevdir) {
			continue;
		}

		devices.push_back(devdir->d_name);
	}

	closedir(ttydir);

#elif defined (__WINDOWS__)
	SerialPort* sport = SerialPort::SerialPortFactory();

	wxArrayString res = sport->GetSerialPortList();

	for (size_t i = 0; i < res.size(); ++i) {
		devices.push_back(res[i].mb_str());
	}

	delete sport;
#endif
}

void ScopeZTSH::SetupDialog()
{
    CraoConfig *craoDlg = new CraoConfig(wxGetActiveWindow(), ctx);

	if (ctx) {
		craoDlg->SetConnectedState();
	}

	craoDlg->curr_device = pConfig->Profile.GetString("/crao/serial", _T(""));
	craoDlg->curr_baud = pConfig->Profile.GetInt("/crao/baud", 9600);
	craoDlg->curr_dbits = pConfig->Profile.GetInt("/crao/dbits", 8);
	craoDlg->curr_sbits = pConfig->Profile.GetInt("/crao/sbits", 1);
	craoDlg->curr_parity = pConfig->Profile.GetString("/crao/parity", "none");
	craoDlg->curr_mbid = pConfig->Profile.GetInt("/crao/mbid", 10);

	EnumerateSerialDevices(craoDlg->tty_devices);

    // initialize with actual values
	craoDlg->LoadSettings();

    if (craoDlg->ShowModal() == wxID_OK) {
		// if OK save the values to the current profile
		craoDlg->SaveSettings();

		pConfig->Profile.SetString("/crao/serial", craoDlg->curr_device);
		pConfig->Profile.SetInt("/crao/baud", craoDlg->curr_baud);
		pConfig->Profile.SetInt("/crao/dbits", craoDlg->curr_dbits);
		pConfig->Profile.SetInt("/crao/sbits", craoDlg->curr_sbits);
		pConfig->Profile.SetString("/crao/parity", craoDlg->curr_parity);
		pConfig->Profile.SetInt("/crao/mbid", craoDlg->curr_mbid);
    }

	craoDlg->Destroy();

	delete craoDlg;
}

bool ScopeZTSH::CanPulseGuide()
{
	return true;
}

static wxString PulseGuideFailedAlertEnabledKey()
{
	// we want the key to be under "/Confirm" so ConfirmDialog::ResetAllDontAskAgain() resets it, but we also want the setting to be per-profile
	return wxString::Format("/Confirm/%d/PulseGuideFailedAlertEnabled", pConfig->GetCurrentProfileId());
}

static void SuppressPulseGuideFailedAlert(long)
{
	pConfig->Global.SetBoolean(PulseGuideFailedAlertEnabledKey(), false);
}

Mount::MOVE_RESULT ScopeZTSH::Guide(GUIDE_DIRECTION direction, int duration)
{
    switch (direction) {
        case EAST:
			if (modbus_write_register(ctx, 11, duration) == -1)  {
				wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
				pFrame->SuppressableAlert(PulseGuideFailedAlertEnabledKey(), _("PulseGuide command to mount has failed - guiding is likely to be ineffective."), SuppressPulseGuideFailedAlert, 0);

				return MOVE_STOP_GUIDING;
			}

			printf("Pulse RA+ for %i\n", duration);
            break;

        case WEST:
			if (modbus_write_register(ctx, 12, duration) == -1) {
				wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
				pFrame->SuppressableAlert(PulseGuideFailedAlertEnabledKey(), _("PulseGuide command to mount has failed - guiding is likely to be ineffective."), SuppressPulseGuideFailedAlert, 0);

				return MOVE_STOP_GUIDING;
			}

			printf("Pulse RA- for %i\n", duration);
            break;

        case NORTH:
			if (modbus_write_register(ctx, 21, duration) == -1) {
				wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
				pFrame->SuppressableAlert(PulseGuideFailedAlertEnabledKey(), _("PulseGuide command to mount has failed - guiding is likely to be ineffective."), SuppressPulseGuideFailedAlert, 0);

				return MOVE_ERROR;
			}

			printf("Pulse DEC+ for %i\n", duration);
            break;

        case SOUTH:
			if (modbus_write_register(ctx, 22, duration) == -1) {
				wxMessageBox(wxString("Failed to communicate with the Mount hardware, modbus error: ") + wxString(modbus_strerror(errno)), _("Error"), wxOK | wxICON_ERROR);
				pFrame->SuppressableAlert(PulseGuideFailedAlertEnabledKey(), _("PulseGuide command to mount has failed - guiding is likely to be ineffective."), SuppressPulseGuideFailedAlert, 0);

				return MOVE_ERROR;
			}

			printf("Pulse DEC- for %i\n", duration);
            break;

        case NONE:
		    printf("error ScopeZTSH::Guide NONE\n");
            break;
    }

    wxMilliSleep(duration);

	return MOVE_OK;
}

#endif

<|endoftext|>


<commit_before>// Copyright 2010-2013 RethinkDB, all rights reserved.
#include "arch/io/disk/pool.hpp"

#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

#include "arch/io/disk.hpp"
#include "config/args.hpp"
#include "containers/printf_buffer.hpp"
#include "logger.hpp"

int blocker_pool_queue_depth(int max_concurrent_io_requests) {
    guarantee(max_concurrent_io_requests > 0);
    guarantee(max_concurrent_io_requests < MAXIMUM_MAX_CONCURRENT_IO_REQUESTS);
    // TODO: Why make this twice MAX_CONCURRENT_IO_REQUESTS?
    return max_concurrent_io_requests * 2;
}

void debug_print(printf_buffer_t *buf,
                 const pool_diskmgr_action_t &action) {
    buf->appendf("pool_diskmgr_action{is_read=%s, fd=%d, count=%zu, "
                 "offset=%" PRIi64 ", errno=%d}",
                 action.get_is_read() ? "true" : "false",
                 action.get_fd(),
                 action.get_count(),
                 action.get_offset(),
                 action.get_succeeded() ? 0 : action.get_io_errno());
}

pool_diskmgr_t::pool_diskmgr_t(linux_event_queue_t *queue,
                               passive_producer_t<action_t *> *_source,
                               int max_concurrent_io_requests)
    : queue_depth(blocker_pool_queue_depth(max_concurrent_io_requests)),
      source(_source),
      blocker_pool(max_concurrent_io_requests, queue),
      n_pending(0) {
    if (source->available->get()) { pump(); }
    source->available->set_callback(this);
}

pool_diskmgr_t::~pool_diskmgr_t() {
    assert_thread();
    source->available->unset_callback();
}

void pool_diskmgr_t::action_t::run() {
    if (wrap_in_datasyncs) {
        int errcode = perform_datasync(fd);
        if (errcode != 0) {
            io_result = -errcode;
            return;
        }
    }

    switch (type) {
    case ACTION_RESIZE: {
        CT_ASSERT(sizeof(off_t) == sizeof(int64_t));
        int res;
        do {
            res = ftruncate(fd, offset);
        } while (res == -1 && get_errno() == EINTR);
        if (res == 0) {
            io_result = 0;
        } else {
            io_result = -get_errno();
            return;
        }
    } break;
    case ACTION_READ:
    case ACTION_WRITE: {
        ssize_t sum = 0;

        iovec *vecs;
        size_t vecs_len;
        get_bufs(&vecs, &vecs_len);
#ifndef USE_WRITEV
#error "USE_WRITEV not defined.  Did you include pool.hpp?"
#elif USE_WRITEV
        const size_t vecs_increment = IOV_MAX;
        size_t len;
        int64_t partial_offset = offset;
        for (size_t i = 0; i < vecs_len; i += len) {
            len = std::min(vecs_increment, vecs_len - i);
            ssize_t res;
            do {
                if (type == ACTION_READ) {
                    res = preadv(fd, vecs + i, len, partial_offset);
                } else {
                    rassert(type == ACTION_WRITE);
                    res = pwritev(fd, vecs + i, len, partial_offset);
                }
            } while (res == -1 && get_errno() == EINTR);

            if (res == -1) {
                io_result = -get_errno();
                return;
            }

            int64_t lensum = 0;
            for (size_t j = i; j < i + len; ++j) {
                lensum += vecs[j].iov_len;
            }
            if (lensum != res && type == ACTION_WRITE) {
                // This happens when running out of disk space.
                // The errno in that case is 0 and doesn't tell us about the
                // real reason for the failed i/o.
                // We set the io_result to be -ENOSPC and print an error stating
                // what actually happened.
                io_result = -ENOSPC;
                logERR("Failed I/O: lensum (%" PRIi64 ") != res (%" PRIi64 ")."
                       " Assuming we ran out of disk space.", lensum, res);
                return;
            }
            guarantee(lensum == res);

            partial_offset += lensum;
            sum += res;
        }
#else  // USE_WRITEV
        guarantee(vecs_len == 1);
        ssize_t res;
        do {
            if (type == ACTION_READ) {
                res = pread(fd, vecs[0].iov_base, vecs[0].iov_len, offset);
            } else {
                rassert(type == ACTION_WRITE);
                res = pwrite(fd, vecs[0].iov_base, vecs[0].iov_len, offset);
            }
        } while (res == -1 && get_errno() == EINTR);

        if (res == -1) {
            io_result = -get_errno();
            return;
        }

        sum = res;
#endif  // USE_WRITEV

        io_result = sum;
    } break;
    default:
        unreachable("Unknown I/O action");
    }

    if (wrap_in_datasyncs) {
        int errcode = perform_datasync(fd);
        if (errcode != 0) {
            io_result = -errcode;
            return;
        }
    }
}

void pool_diskmgr_action_t::done() {
    parent->assert_thread();
    parent->n_pending--;
    parent->pump();
    parent->done_fun(this);
}

void pool_diskmgr_t::on_source_availability_changed() {
    assert_thread();
    /* This is called when the queue used to be empty but now has requests on
    it, and also when the queue's last request is consumed. */
    if (source->available->get()) pump();
}

void pool_diskmgr_t::pump() {
    assert_thread();
    while (source->available->get() && n_pending < queue_depth) {
        action_t *a = source->pop();
        a->parent = this;
        n_pending++;
        blocker_pool.do_job(a);
    }
}

<commit_msg>Use %zd for ssize_t<commit_after>// Copyright 2010-2013 RethinkDB, all rights reserved.
#include "arch/io/disk/pool.hpp"

#include <fcntl.h>
#include <limits.h>
#include <sys/types.h>
#include <sys/uio.h>
#include <unistd.h>

#include "arch/io/disk.hpp"
#include "config/args.hpp"
#include "containers/printf_buffer.hpp"
#include "logger.hpp"

int blocker_pool_queue_depth(int max_concurrent_io_requests) {
    guarantee(max_concurrent_io_requests > 0);
    guarantee(max_concurrent_io_requests < MAXIMUM_MAX_CONCURRENT_IO_REQUESTS);
    // TODO: Why make this twice MAX_CONCURRENT_IO_REQUESTS?
    return max_concurrent_io_requests * 2;
}

void debug_print(printf_buffer_t *buf,
                 const pool_diskmgr_action_t &action) {
    buf->appendf("pool_diskmgr_action{is_read=%s, fd=%d, count=%zu, "
                 "offset=%" PRIi64 ", errno=%d}",
                 action.get_is_read() ? "true" : "false",
                 action.get_fd(),
                 action.get_count(),
                 action.get_offset(),
                 action.get_succeeded() ? 0 : action.get_io_errno());
}

pool_diskmgr_t::pool_diskmgr_t(linux_event_queue_t *queue,
                               passive_producer_t<action_t *> *_source,
                               int max_concurrent_io_requests)
    : queue_depth(blocker_pool_queue_depth(max_concurrent_io_requests)),
      source(_source),
      blocker_pool(max_concurrent_io_requests, queue),
      n_pending(0) {
    if (source->available->get()) { pump(); }
    source->available->set_callback(this);
}

pool_diskmgr_t::~pool_diskmgr_t() {
    assert_thread();
    source->available->unset_callback();
}

void pool_diskmgr_t::action_t::run() {
    if (wrap_in_datasyncs) {
        int errcode = perform_datasync(fd);
        if (errcode != 0) {
            io_result = -errcode;
            return;
        }
    }

    switch (type) {
    case ACTION_RESIZE: {
        CT_ASSERT(sizeof(off_t) == sizeof(int64_t));
        int res;
        do {
            res = ftruncate(fd, offset);
        } while (res == -1 && get_errno() == EINTR);
        if (res == 0) {
            io_result = 0;
        } else {
            io_result = -get_errno();
            return;
        }
    } break;
    case ACTION_READ:
    case ACTION_WRITE: {
        ssize_t sum = 0;

        iovec *vecs;
        size_t vecs_len;
        get_bufs(&vecs, &vecs_len);
#ifndef USE_WRITEV
#error "USE_WRITEV not defined.  Did you include pool.hpp?"
#elif USE_WRITEV
        const size_t vecs_increment = IOV_MAX;
        size_t len;
        int64_t partial_offset = offset;
        for (size_t i = 0; i < vecs_len; i += len) {
            len = std::min(vecs_increment, vecs_len - i);
            ssize_t res;
            do {
                if (type == ACTION_READ) {
                    res = preadv(fd, vecs + i, len, partial_offset);
                } else {
                    rassert(type == ACTION_WRITE);
                    res = pwritev(fd, vecs + i, len, partial_offset);
                }
            } while (res == -1 && get_errno() == EINTR);

            if (res == -1) {
                io_result = -get_errno();
                return;
            }

            int64_t lensum = 0;
            for (size_t j = i; j < i + len; ++j) {
                lensum += vecs[j].iov_len;
            }
            if (lensum != res && type == ACTION_WRITE) {
                // This happens when running out of disk space.
                // The errno in that case is 0 and doesn't tell us about the
                // real reason for the failed i/o.
                // We set the io_result to be -ENOSPC and print an error stating
                // what actually happened.
                io_result = -ENOSPC;
                logERR("Failed I/O: lensum (%" PRIi64 ") != res (%zd)."
                       " Assuming we ran out of disk space.", lensum, res);
                return;
            }
            guarantee(lensum == res);

            partial_offset += lensum;
            sum += res;
        }
#else  // USE_WRITEV
        guarantee(vecs_len == 1);
        ssize_t res;
        do {
            if (type == ACTION_READ) {
                res = pread(fd, vecs[0].iov_base, vecs[0].iov_len, offset);
            } else {
                rassert(type == ACTION_WRITE);
                res = pwrite(fd, vecs[0].iov_base, vecs[0].iov_len, offset);
            }
        } while (res == -1 && get_errno() == EINTR);

        if (res == -1) {
            io_result = -get_errno();
            return;
        }

        sum = res;
#endif  // USE_WRITEV

        io_result = sum;
    } break;
    default:
        unreachable("Unknown I/O action");
    }

    if (wrap_in_datasyncs) {
        int errcode = perform_datasync(fd);
        if (errcode != 0) {
            io_result = -errcode;
            return;
        }
    }
}

void pool_diskmgr_action_t::done() {
    parent->assert_thread();
    parent->n_pending--;
    parent->pump();
    parent->done_fun(this);
}

void pool_diskmgr_t::on_source_availability_changed() {
    assert_thread();
    /* This is called when the queue used to be empty but now has requests on
    it, and also when the queue's last request is consumed. */
    if (source->available->get()) pump();
}

void pool_diskmgr_t::pump() {
    assert_thread();
    while (source->available->get() && n_pending < queue_depth) {
        action_t *a = source->pop();
        a->parent = this;
        n_pending++;
        blocker_pool.do_job(a);
    }
}

<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	Arithmetic テンプレート @n
			※テキストの数式を展開して、計算結果を得る。@n
			NVAL には、Boost Multiprecision Library を利用する事を前提にしている。
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2015, 2021 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/bitset.hpp"

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	Arithmetic クラス
		@param[in]	NVAL	基本型
		@param[in]	SYMBOL	変数クラス
		@param[in]	FUNC	関数クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class NVAL, class SYMBOL, class FUNC>
	struct basic_arith {

		static const uint32_t NUMBER_NUM = 50;  ///< 最大桁数
		static const uint32_t NEST_MAX   = 10;  ///< 最大ネスト

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	エラー・タイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class error : uint8_t {
			fatal,				///< エラー
			number_fatal,		///< 数字の変換に関するエラー
			zero_divide,		///< ０除算エラー
			binary_fatal,		///< ２進データの変換に関するエラー
			octal_fatal,		///< ８進データの変換に関するエラー
			hexdecimal_fatal,	///< １６進データの変換に関するエラー
			num_fatal,			///< 数値の変換に関するエラー
			nest_fatal,			///< 深度が制限を超えたエラー
			symbol_fatal,		///< シンボルデータの変換に関するエラー
			func_fatal,			///< 関数の変換に関するエラー
		};

		typedef bitset<uint16_t, error> error_t;

	private:

		SYMBOL&		symbol_;
		FUNC&		func_;

		const char*		tx_;
		char			ch_;

		error_t		error_;

		NVAL		value_;

		bool		str_;

		uint32_t	nest_;

		// 関数内パラメーターの取得
		bool param_(char* dst, uint32_t len) noexcept
		{
			if(ch_ != '(') return false;

			while(ch_ != 0) {
				--len;
				if(len == 0) break;
			}

			return true;
		}

		void func_sub_(typename FUNC::NAME fc, NVAL& nval)
		{
			ch_ = *tx_++;
			if(ch_ == '(') {
				ch_ = *tx_++;
				auto param = expression_();
				if(ch_ == ')') {
					ch_ = *tx_++;
					if(!func_(fc, param, nval)) {
						error_.set(error::func_fatal);
					}
				} else {
					error_.set(error::fatal);
				}
			} else {
				error_.set(error::func_fatal);
			}
		}

		NVAL number_() noexcept
		{
			bool minus = false;
			char tmp[NUMBER_NUM];

			// 符号、反転の判定
			if(ch_ == '-') {
				minus = true;
				ch_ = *tx_++;
			} else if(ch_ == '+') {
				ch_ = *tx_++;
			}

			NVAL nval;
			if(str_) {  // 変数名、関数名が文字列の場合
				if((ch_ >= '0' && ch_ <= '9') || ch_ == '(') {  // 数値のチェック

				} else {
					typename SYMBOL::NAME sc;
					auto tmp = symbol_.get_code(tx_ - 1, sc);
					if(symbol_(sc, nval)) {
						tx_ = tmp;
						ch_ = *tx_++;
						if(minus) { nval = -nval; }
						return nval;
					} else {
						typename FUNC::NAME fc;
						tx_ = func_.get_code(tx_ - 1, fc);
						if(fc != FUNC::NAME::NONE) {
							func_sub_(fc, nval);
							if(minus) { nval = -nval; }
							return nval;
						}
					}
					error_.set(error::symbol_fatal);
					if(minus) { nval = -nval; }
					return nval;
				}
			}
			if(static_cast<uint8_t>(ch_) >= 0x80) {  // symbol?, func?
				if(static_cast<uint8_t>(ch_) >= 0xC0) {  // func ?
					auto fc = static_cast<typename FUNC::NAME>(ch_);
					func_sub_(fc, nval);
				} else {  // to symbol
					if(symbol_(static_cast<typename SYMBOL::NAME>(ch_), nval)) {
						ch_ = *tx_++;
					} else {
						error_.set(error::symbol_fatal);
					}
				}
				if(minus) { nval = -nval; }
				return nval;
			}

			if(ch_ == '(') {
				nval = factor_();
			} else {
				uint32_t idx = 0;
				while(ch_ != 0) {
					if(ch_ == '+') break;
					else if(ch_ == '-') break;
					else if(ch_ == '*') break;
					else if(ch_ == '/') break;
					else if(ch_ == ')') break;
					else if(ch_ == '^') break;
					else if((ch_ >= '0' && ch_ <= '9') || ch_=='.' || ch_=='e' || ch_=='E') {
						tmp[idx] = ch_;
						idx++;
					} else {
						error_.set(error::fatal);
						break;
					}
					ch_ = *tx_++;
				}
				tmp[idx] = 0;
				if(error_() == 0) {
					nval.assign(tmp);
				}
			}

			if(minus) { nval = -nval; }

			return nval;
		}

		auto factor_() noexcept
		{
			NVAL v(0);
			if(ch_ == '(') {
				ch_ = *tx_++;
				v = expression_();
				if(ch_ == ')') {
					ch_ = *tx_++;
				} else {
					error_.set(error::fatal);
				}
			} else {
				v = number_();
			}
			return v;
		}

		NVAL term_() noexcept
		{
			NVAL v = factor_();
			while(error_() == 0) {
				switch(ch_) {
				case '*':
					ch_ = *tx_++;
					v *= factor_();
					break;
#if 0
				case '%':
					ch_ = *tx_++;
					tmp = factor_();
					if(tmp == 0) {
						error_.set(error::zero_divide);
						break;
					}
					v %= tmp;
					break;
#endif
				case '/':
					ch_ = *tx_++;
					if(ch_ == '/') {
						ch_ = *tx_++;
						auto tmp = factor_();
						if(tmp == 0) {
							error_.set(error::zero_divide);
							break;
						}
					} else {
						auto tmp = factor_();
						if(tmp == 0) {
							error_.set(error::zero_divide);
							break;
						}
						v /= tmp;
					}
					break;
				case '^':
					ch_ = *tx_++;
					{
						auto n = factor_();
						v.pow(n);
					}
					break;
#if 0
				case '<':
					ch_ = *tx_++;
					if(ch_ == '<') {
						ch_ = *tx_++;
						v <<= factor_();
					} else {
						error_.set(error::fatal);
					}
					break;
				case '>':
					ch_ = *tx_++;
					if(ch_ == '>') {
						ch_ = *tx_++;
						v <<= factor_();
					} else {
						error_.set(error::fatal);
					}
					break;
#endif
				default:
					return v;
					break;
				}
			}
			return v;
		}

		NVAL expression_() noexcept
		{
			++nest_;
			if(nest_ >= NEST_MAX) {
				error_.set(error::nest_fatal);
			}
			NVAL v = term_();
			while(error_() == 0) {
				switch(ch_) {
				case '+':
					ch_ = *tx_++;
					v += term_();
					break;
				case '-':
					ch_ = *tx_++;
					v -= term_();
					break;
#if 0
				case '&':
					ch_ = *tx_++;
					v &= term_();
					break;
				case '^':
					ch_ = *tx_++;
					v ^= term_();
					break;
				case '|':
					ch_ = *tx_++;
					v |= term_();
					break;
#endif
				default:
					return v;
					break;
				}
			}
			return v;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	func	関数クラス
		*/
		//-----------------------------------------------------------------//
		basic_arith(SYMBOL& symbol, FUNC& func) noexcept : symbol_(symbol), func_(func),
			tx_(nullptr), ch_(0), error_(), value_(), str_(false), nest_(0)
		{ }

		//-----------------------------------------------------------------//
		/*!
			@brief	解析を開始 @n
					・高速化の為、シンボル名、関数名は修飾コードを使う。@n
					・シンボル名、関数名を文字列として扱う場合、「str = true」とする。
			@param[in]	text	解析テキスト
			@param[in]	str		変数名、関数名を文字列とした扱う場合「true」
			@return	文法にエラーがあった場合、「false」
		*/
		//-----------------------------------------------------------------//
		bool analize(const char* text, bool str = false) noexcept
		{
			if(text == nullptr) {
				error_.set(error::fatal);
				return false;
			}
			tx_ = text;
			str_ = str;

			error_.clear();
			nest_ = 0;

			ch_ = *tx_++;
			if(ch_ != 0) {
				value_ = expression_();
			} else {
				error_.set(error::fatal);
			}

			if(error_() != 0) {
				return false;
			} else if(ch_ != 0) {
				error_.set(error::fatal);
				return false;
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	エラーを受け取る
			@return エラー
		*/
		//-----------------------------------------------------------------//
		const error_t& get_error() const noexcept { return error_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	エラーメッセージを取得
			@return エラーメッセージ
		*/
		//-----------------------------------------------------------------//
		template <class STR>
		STR get_error() const noexcept {
			STR str;
			return str;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	埋め込まれた、シンボル、関数名を展開
			@param[in]	in		入力文字列
			@param[out]	out		展開文字列
			@param[in]	len		展開文字列サイズ
			@return	成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool parse(const char* in, char* out, uint32_t len) const noexcept
		{
			char ch;
			while(len > 1 && (ch = *in++) != 0) {
				uint8_t n = static_cast<uint8_t>(ch);
				if(n < 0x80) {
					*out++ = ch;
					len--;
				} else if(n < 0xc0) {  // シンボル

				} else {  // 関数

				}
			}
			*out = 0;
			return len > 1;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	() で結果を取得
			@return	結果
		*/
		//-----------------------------------------------------------------//
		NVAL operator() () const noexcept { return value_; }
	};
}
<commit_msg>Update: command line analize<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	Arithmetic テンプレート @n
			※テキストの数式を展開して、計算結果を得る。@n
			NVAL には、Boost Multiprecision Library を利用する事を前提にしている。
    @author 平松邦仁 (hira@rvf-rc45.net)
	@copyright	Copyright (C) 2015, 2021 Kunihito Hiramatsu @n
				Released under the MIT license @n
				https://github.com/hirakuni45/RX/blob/master/LICENSE
*/
//=====================================================================//
#include <cstdint>
#include "common/bitset.hpp"

namespace utils {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	Arithmetic クラス
		@param[in]	NVAL	基本型
		@param[in]	SYMBOL	変数クラス
		@param[in]	FUNC	関数クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class NVAL, class SYMBOL, class FUNC>
	struct basic_arith {

		static const uint32_t NUMBER_NUM = 50;  ///< 最大桁数
		static const uint32_t NEST_MAX   = 10;  ///< 最大ネスト

		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		/*!
			@brief	エラー・タイプ
		*/
		//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
		enum class error : uint8_t {
			fatal,				///< エラー
			number_fatal,		///< 数字の変換に関するエラー
			zero_divide,		///< ０除算エラー
			binary_fatal,		///< ２進データの変換に関するエラー
			octal_fatal,		///< ８進データの変換に関するエラー
			hexdecimal_fatal,	///< １６進データの変換に関するエラー
			num_fatal,			///< 数値の変換に関するエラー
			nest_fatal,			///< 深度が制限を超えたエラー
			symbol_fatal,		///< シンボルデータの変換に関するエラー
			func_fatal,			///< 関数の変換に関するエラー
		};

		typedef bitset<uint16_t, error> error_t;

	private:

		SYMBOL&		symbol_;
		FUNC&		func_;

		const char*		tx_;
		char			ch_;

		error_t		error_;

		NVAL		value_;

		uint32_t	nest_;

		// 関数内パラメーターの取得
		bool param_(char* dst, uint32_t len) noexcept
		{
			if(ch_ != '(') return false;

			while(ch_ != 0) {
				--len;
				if(len == 0) break;
			}

			return true;
		}

		void func_sub_(typename FUNC::NAME fc, NVAL& nval)
		{
			ch_ = *tx_++;
			if(ch_ == '(') {
				ch_ = *tx_++;
				auto param = expression_();
				if(ch_ == ')') {
					ch_ = *tx_++;
					if(!func_(fc, param, nval)) {
						error_.set(error::func_fatal);
					}
				} else {
					error_.set(error::fatal);
				}
			} else {
				error_.set(error::func_fatal);
			}
		}

		NVAL number_() noexcept
		{
			bool minus = false;
			char tmp[NUMBER_NUM];

			// 符号、反転の判定
			if(ch_ == '-') {
				minus = true;
				ch_ = *tx_++;
			} else if(ch_ == '+') {
				ch_ = *tx_++;
			}

			NVAL nval;
			if((ch_ >= '0' && ch_ <= '9') || ch_ == '(') {  // 数値のチェック

			} else if(ch_ <= 0x7f) {  // 通常の文字列の場合
				typename SYMBOL::NAME sc;
				auto tmp = symbol_.get_code(tx_ - 1, sc);
				if(symbol_(sc, nval)) {
					tx_ = tmp;
					ch_ = *tx_++;
					if(minus) { nval = -nval; }
					return nval;
				} else {
					typename FUNC::NAME fc;
					auto tmp = func_.get_code(tx_ - 1, fc);
					if(fc != FUNC::NAME::NONE) {
						tx_ = tmp;
						func_sub_(fc, nval);
						if(minus) { nval = -nval; }
						return nval;
					}
				}
				error_.set(error::symbol_fatal);
				return nval;
			} else if(static_cast<uint8_t>(ch_) >= 0x80) {  // symbol?, func?
				if(static_cast<uint8_t>(ch_) >= 0xC0) {  // func ?
					auto fc = static_cast<typename FUNC::NAME>(ch_);
					func_sub_(fc, nval);
				} else {  // to symbol
					if(symbol_(static_cast<typename SYMBOL::NAME>(ch_), nval)) {
						ch_ = *tx_++;
					} else {
						error_.set(error::symbol_fatal);
					}
				}
				if(minus) { nval = -nval; }
				return nval;
			}

			if(ch_ == '(') {
				nval = factor_();
			} else {
				uint32_t idx = 0;
				while(ch_ != 0) {
					if(ch_ == '+') break;
					else if(ch_ == '-') break;
					else if(ch_ == '*') break;
					else if(ch_ == '/') break;
					else if(ch_ == ')') break;
					else if(ch_ == '^') break;
					else if((ch_ >= '0' && ch_ <= '9') || ch_=='.' || ch_=='e' || ch_=='E') {
						tmp[idx] = ch_;
						idx++;
					} else {
						error_.set(error::fatal);
						break;
					}
					ch_ = *tx_++;
				}
				tmp[idx] = 0;
				if(error_() == 0) {
					nval.assign(tmp);
				}
			}

			if(minus) { nval = -nval; }

			return nval;
		}

		auto factor_() noexcept
		{
			NVAL v(0);
			if(ch_ == '(') {
				ch_ = *tx_++;
				v = expression_();
				if(ch_ == ')') {
					ch_ = *tx_++;
				} else {
					error_.set(error::fatal);
				}
			} else {
				v = number_();
			}
			return v;
		}

		NVAL term_() noexcept
		{
			NVAL v = factor_();
			while(error_() == 0) {
				switch(ch_) {
				case '*':
					ch_ = *tx_++;
					v *= factor_();
					break;
#if 0
				case '%':
					ch_ = *tx_++;
					tmp = factor_();
					if(tmp == 0) {
						error_.set(error::zero_divide);
						break;
					}
					v %= tmp;
					break;
#endif
				case '/':
					ch_ = *tx_++;
					if(ch_ == '/') {
						ch_ = *tx_++;
						auto tmp = factor_();
						if(tmp == 0) {
							error_.set(error::zero_divide);
							break;
						}
					} else {
						auto tmp = factor_();
						if(tmp == 0) {
							error_.set(error::zero_divide);
							break;
						}
						v /= tmp;
					}
					break;
				case '^':
					ch_ = *tx_++;
					{
						auto n = factor_();
						v.pow(n);
					}
					break;
#if 0
				case '<':
					ch_ = *tx_++;
					if(ch_ == '<') {
						ch_ = *tx_++;
						v <<= factor_();
					} else {
						error_.set(error::fatal);
					}
					break;
				case '>':
					ch_ = *tx_++;
					if(ch_ == '>') {
						ch_ = *tx_++;
						v <<= factor_();
					} else {
						error_.set(error::fatal);
					}
					break;
#endif
				default:
					return v;
					break;
				}
			}
			return v;
		}

		NVAL expression_() noexcept
		{
			++nest_;
			if(nest_ >= NEST_MAX) {
				error_.set(error::nest_fatal);
			}
			NVAL v = term_();
			while(error_() == 0) {
				switch(ch_) {
				case '+':
					ch_ = *tx_++;
					v += term_();
					break;
				case '-':
					ch_ = *tx_++;
					v -= term_();
					break;
#if 0
				case '&':
					ch_ = *tx_++;
					v &= term_();
					break;
				case '^':
					ch_ = *tx_++;
					v ^= term_();
					break;
				case '|':
					ch_ = *tx_++;
					v |= term_();
					break;
#endif
				default:
					return v;
					break;
				}
			}
			return v;
		}

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
			@param[in]	func	関数クラス
		*/
		//-----------------------------------------------------------------//
		basic_arith(SYMBOL& symbol, FUNC& func) noexcept : symbol_(symbol), func_(func),
			tx_(nullptr), ch_(0), error_(), value_(), nest_(0)
		{ }

		//-----------------------------------------------------------------//
		/*!
			@brief	解析を開始 @n
					・高速化の場合、シンボル名、関数名は修飾コードを使う事が出来る。
			@param[in]	text	解析テキスト
			@return	文法にエラーがあった場合、「false」
		*/
		//-----------------------------------------------------------------//
		bool analize(const char* text) noexcept
		{
			if(text == nullptr) {
				error_.set(error::fatal);
				return false;
			}
			tx_ = text;

			error_.clear();
			nest_ = 0;

			ch_ = *tx_++;
			if(ch_ != 0) {
				value_ = expression_();
			} else {
				error_.set(error::fatal);
			}

			if(error_() != 0) {
				return false;
			} else if(ch_ != 0) {
				error_.set(error::fatal);
				return false;
			}
			return true;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	エラーを受け取る
			@return エラー
		*/
		//-----------------------------------------------------------------//
		const error_t& get_error() const noexcept { return error_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	エラーメッセージを取得
			@return エラーメッセージ
		*/
		//-----------------------------------------------------------------//
		template <class STR>
		STR get_error() const noexcept {
			STR str;
			return str;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	埋め込まれた、シンボル、関数名を展開
			@param[in]	in		入力文字列
			@param[out]	out		展開文字列
			@param[in]	len		展開文字列サイズ
			@return	成功なら「true」
		*/
		//-----------------------------------------------------------------//
		bool parse(const char* in, char* out, uint32_t len) const noexcept
		{
			char ch;
			while(len > 1 && (ch = *in++) != 0) {
				uint8_t n = static_cast<uint8_t>(ch);
				if(n < 0x80) {
					*out++ = ch;
					len--;
				} else if(n < 0xc0) {  // シンボル

				} else {  // 関数

				}
			}
			*out = 0;
			return len > 1;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	() で結果を取得
			@return	結果
		*/
		//-----------------------------------------------------------------//
		NVAL operator() () const noexcept { return value_; }
	};
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 * Copyright (c) 2014-2015 Kohei Yoshida
 *
 * 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 <cstring>
#include <algorithm>

#include <cassert>

namespace mdds {

namespace {

// don't use it!
// Implementation detail!
template<typename _ValueT>
bool compare(const typename sorted_string_map<_ValueT>::entry& entry1,
        const typename sorted_string_map<_ValueT>::entry& entry2)
{
    if (entry1.keylen != entry2.keylen)
    {
        typename sorted_string_map<_ValueT>::size_type keylen = std::min(entry1.keylen, entry2.keylen);
        int ret = std::memcmp(entry1.key, entry2.key, keylen);
        if (ret == 0)
            return entry1.keylen < entry2.keylen;

        return ret < 0;
    }
    else
    {
        return std::memcmp(entry1.key, entry2.key, entry1.keylen) < 0;
    }
}

}

template<typename _ValueT>
sorted_string_map<_ValueT>::sorted_string_map(const entry* entries, size_type entry_size, value_type null_value) :
    m_entries(entries),
    m_null_value(null_value),
    m_entry_size(entry_size),
    m_entry_end(m_entries+m_entry_size)
{
#ifdef _GLIBCXX_DEBUG
    assert(std::is_sorted(m_entries, m_entry_end, compare<_ValueT>));
#endif
}

template<typename _ValueT>
typename sorted_string_map<_ValueT>::value_type
sorted_string_map<_ValueT>::find(const char* input, size_type len) const
{
    if (m_entry_size == 0)
        return m_null_value;

    entry ent;
    ent.key = input;
    ent.keylen = len;
    ent.value = 0;

    const entry* val = std::lower_bound(m_entries, m_entry_end, ent, compare<_ValueT>);
    if (val == m_entry_end || val->keylen != len || std::memcmp(val->key, input, len))
        return m_null_value;

    return val->value;
}

template<typename _ValueT>
typename sorted_string_map<_ValueT>::size_type
sorted_string_map<_ValueT>::size() const
{
    return m_entry_size;
}

}
<commit_msg>Use detail namespace for impl. detail & avoid setting entry value.<commit_after>/*************************************************************************
 *
 * Copyright (c) 2014-2015 Kohei Yoshida
 *
 * 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 <cstring>
#include <algorithm>

#include <cassert>

namespace mdds {

namespace detail {

// don't use it!
// Implementation detail!
template<typename _ValueT>
bool compare(const typename sorted_string_map<_ValueT>::entry& entry1,
        const typename sorted_string_map<_ValueT>::entry& entry2)
{
    if (entry1.keylen != entry2.keylen)
    {
        typename sorted_string_map<_ValueT>::size_type keylen = std::min(entry1.keylen, entry2.keylen);
        int ret = std::memcmp(entry1.key, entry2.key, keylen);
        if (ret == 0)
            return entry1.keylen < entry2.keylen;

        return ret < 0;
    }
    else
    {
        return std::memcmp(entry1.key, entry2.key, entry1.keylen) < 0;
    }
}

}

template<typename _ValueT>
sorted_string_map<_ValueT>::sorted_string_map(const entry* entries, size_type entry_size, value_type null_value) :
    m_entries(entries),
    m_null_value(null_value),
    m_entry_size(entry_size),
    m_entry_end(m_entries+m_entry_size)
{
#ifdef _GLIBCXX_DEBUG
    assert(std::is_sorted(m_entries, m_entry_end, compare<_ValueT>));
#endif
}

template<typename _ValueT>
typename sorted_string_map<_ValueT>::value_type
sorted_string_map<_ValueT>::find(const char* input, size_type len) const
{
    if (m_entry_size == 0)
        return m_null_value;

    entry ent;
    ent.key = input;
    ent.keylen = len;

    const entry* val = std::lower_bound(m_entries, m_entry_end, ent, detail::compare<_ValueT>);
    if (val == m_entry_end || val->keylen != len || std::memcmp(val->key, input, len))
        return m_null_value;

    return val->value;
}

template<typename _ValueT>
typename sorted_string_map<_ValueT>::size_type
sorted_string_map<_ValueT>::size() const
{
    return m_entry_size;
}

}
<|endoftext|>


<commit_before>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
 *
 *  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.
 *
 *      * The names of its contributors may not 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.
 *
 */

#include <libmemcached/common.h>

#include <libmemcached/options.hpp>
#include <libmemcached/virtual_bucket.h>

static inline bool _memcached_init(memcached_st *self)
{
  self->state.is_purging= false;
  self->state.is_processing_input= false;
  self->state.is_time_for_rebuild= false;

  self->flags.auto_eject_hosts= false;
  self->flags.binary_protocol= false;
  self->flags.buffer_requests= false;
  self->flags.hash_with_namespace= false;
  self->flags.no_block= false;
  self->flags.reply= true;
  self->flags.randomize_replica_read= false;
  self->flags.support_cas= false;
  self->flags.tcp_nodelay= false;
  self->flags.use_sort_hosts= false;
  self->flags.use_udp= false;
  self->flags.verify_key= false;
  self->flags.tcp_keepalive= false;
  self->flags.is_aes= false;
  self->flags.is_fetching_version= false;

  self->virtual_bucket= NULL;

  self->distribution= MEMCACHED_DISTRIBUTION_MODULA;

  if (hashkit_create(&self->hashkit) == NULL)
  {
    return false;
  }

  self->server_info.version= 0;

  self->ketama.continuum= NULL;
  self->ketama.continuum_count= 0;
  self->ketama.continuum_points_counter= 0;
  self->ketama.next_distribution_rebuild= 0;
  self->ketama.weighted_= false;

  self->number_of_hosts= 0;
  self->servers= NULL;
  self->last_disconnected_server= NULL;

  self->snd_timeout= 0;
  self->rcv_timeout= 0;
  self->server_failure_limit= MEMCACHED_SERVER_FAILURE_LIMIT;
  self->query_id= 1; // 0 is considered invalid

  /* TODO, Document why we picked these defaults */
  self->io_msg_watermark= 500;
  self->io_bytes_watermark= 65 * 1024;

  self->tcp_keepidle= 0;

  self->io_key_prefetch= 0;
  self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
  self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
  self->retry_timeout= MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT;
  self->dead_timeout= MEMCACHED_SERVER_FAILURE_DEAD_TIMEOUT;

  self->send_size= -1;
  self->recv_size= -1;

  self->user_data= NULL;
  self->number_of_replicas= 0;

  self->allocators= memcached_allocators_return_default();

  self->on_clone= NULL;
  self->on_cleanup= NULL;
  self->get_key_failure= NULL;
  self->delete_trigger= NULL;
  self->callbacks= NULL;
  self->sasl.callbacks= NULL;
  self->sasl.is_allocated= false;

  self->error_messages= NULL;
  self->_namespace= NULL;
  self->configure.initial_pool_size= 1;
  self->configure.max_pool_size= 1;
  self->configure.version= -1;
  self->configure.filename= NULL;
  self->configure.source_address = NULL;

  return true;
}

static void __memcached_free(memcached_st *ptr, bool release_st)
{
  /* If we have anything open, lets close it now */
  send_quit(ptr);
  memcached_instance_list_free(memcached_instance_list(ptr), memcached_instance_list_count(ptr));
  memcached_result_free(&ptr->result);

  memcached_virtual_bucket_free(ptr);

  memcached_instance_free((org::libmemcached::Instance*)ptr->last_disconnected_server);

  if (ptr->on_cleanup)
  {
    ptr->on_cleanup(ptr);
  }

  libmemcached_free(ptr, ptr->ketama.continuum);

  memcached_array_free(ptr->_namespace);
  ptr->_namespace= NULL;

  memcached_error_free(*ptr);

  if (LIBMEMCACHED_WITH_SASL_SUPPORT and ptr->sasl.callbacks)
  {
    memcached_destroy_sasl_auth_data(ptr);
  }

  if (release_st)
  {
    memcached_array_free(ptr->configure.filename);
    ptr->configure.filename= NULL;
  }

  hashkit_free(&ptr->hashkit);

  if (memcached_is_allocated(ptr) and release_st)
  {
    libmemcached_free(ptr, ptr);
  }
}

memcached_st *memcached_create(memcached_st *ptr)
{
  if (ptr)
  {
    ptr->options.is_allocated= false;
  }
  else
  {
    ptr= (memcached_st *)libmemcached_xmalloc(NULL, memcached_st);

    if (ptr == NULL)
    {
      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
    }

    ptr->options.is_allocated= true;
  }

  if (_memcached_init(ptr) == false)
  {
    memcached_free(ptr);
    return NULL;
  }

  if (memcached_result_create(ptr, &ptr->result) == NULL)
  {
    memcached_free(ptr);
    return NULL;
  }

  WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);

  return ptr;
}

memcached_st *memcached(const char *string, size_t length)
{
  if (length == 0 and string)
  {
    return NULL;
  }

  if (length and string == NULL)
  {
    return NULL;
  }

  if (length == 0)
  {
    if (bool(getenv("LIBMEMCACHED")))
    {
      string= getenv("LIBMEMCACHED");
      length= string ? strlen(string) : 0;
    }
  }

  memcached_st *memc= memcached_create(NULL);
  if (memc == NULL)
  {
    return NULL;
  }

  if (length == 0 or string == NULL)
  {
    return memc;
  }

  memcached_return_t rc= memcached_parse_configuration(memc, string, length);
  if (memcached_success(rc) and memcached_parse_filename(memc))
  {
    rc= memcached_parse_configure_file(*memc, memcached_parse_filename(memc), memcached_parse_filename_length(memc));
  }

  if (memcached_failed(rc))
  {
    memcached_free(memc);
    return NULL;
  }

  return memc;
}

memcached_return_t memcached_reset(memcached_st *ptr)
{
  WATCHPOINT_ASSERT(ptr);
  if (ptr == NULL)
  {
    return MEMCACHED_INVALID_ARGUMENTS;
  }

  bool stored_is_allocated= memcached_is_allocated(ptr);
  uint64_t query_id= ptr->query_id;
  __memcached_free(ptr, false);
  memcached_create(ptr);
  memcached_set_allocated(ptr, stored_is_allocated);
  ptr->query_id= query_id;

  if (ptr->configure.filename)
  {
    return memcached_parse_configure_file(*ptr, memcached_param_array(ptr->configure.filename));
  }

  return MEMCACHED_SUCCESS;
}

void memcached_servers_reset(memcached_st *self)
{
  if (self)
  {
    memcached_instance_list_free(memcached_instance_list(self), self->number_of_hosts);

    memcached_instance_set(self, NULL);
    self->number_of_hosts= 0;
    memcached_instance_free((org::libmemcached::Instance*)self->last_disconnected_server);
    self->last_disconnected_server= NULL;
  }
}

void memcached_reset_last_disconnected_server(memcached_st *self)
{
  if (self)
  {
    memcached_instance_free((org::libmemcached::Instance*)self->last_disconnected_server);
    self->last_disconnected_server= NULL;
  }
}

void memcached_free(memcached_st *ptr)
{
  if (ptr)
  {
    __memcached_free(ptr, true);
  }
}

/*
  clone is the destination, while source is the structure to clone.
  If source is NULL the call is the same as if a memcached_create() was
  called.
*/
memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
{
  if (source == NULL)
  {
    return memcached_create(clone);
  }

  if (clone and memcached_is_allocated(clone))
  {
    return NULL;
  }

  memcached_st *new_clone= memcached_create(clone);

  if (new_clone == NULL)
  {
    return NULL;
  }

  new_clone->flags= source->flags;
  new_clone->send_size= source->send_size;
  new_clone->recv_size= source->recv_size;
  new_clone->poll_timeout= source->poll_timeout;
  new_clone->connect_timeout= source->connect_timeout;
  new_clone->retry_timeout= source->retry_timeout;
  new_clone->dead_timeout= source->dead_timeout;
  new_clone->distribution= source->distribution;

  if (hashkit_clone(&new_clone->hashkit, &source->hashkit) == NULL)
  {
    memcached_free(new_clone);
    return NULL;
  }

  new_clone->user_data= source->user_data;

  new_clone->snd_timeout= source->snd_timeout;
  new_clone->rcv_timeout= source->rcv_timeout;

  new_clone->on_clone= source->on_clone;
  new_clone->on_cleanup= source->on_cleanup;

  new_clone->allocators= source->allocators;

  new_clone->get_key_failure= source->get_key_failure;
  new_clone->delete_trigger= source->delete_trigger;
  new_clone->server_failure_limit= source->server_failure_limit;
  new_clone->io_msg_watermark= source->io_msg_watermark;
  new_clone->io_bytes_watermark= source->io_bytes_watermark;
  new_clone->io_key_prefetch= source->io_key_prefetch;
  new_clone->number_of_replicas= source->number_of_replicas;
  new_clone->tcp_keepidle= source->tcp_keepidle;

  if (memcached_server_count(source))
  {
    if (memcached_failed(memcached_push(new_clone, source)))
    {
      return NULL;
    }
  }

  new_clone->_namespace= memcached_array_clone(new_clone, source->_namespace);
  new_clone->configure.filename= memcached_array_clone(new_clone, source->_namespace);
  new_clone->configure.version= source->configure.version;

  if (LIBMEMCACHED_WITH_SASL_SUPPORT and source->sasl.callbacks)
  {
    if (memcached_failed(memcached_clone_sasl(new_clone, source)))
    {
      memcached_free(new_clone);
      return NULL;
    }
  }

  if (memcached_failed(run_distribution(new_clone)))
  {
    memcached_free(new_clone);

    return NULL;
  }

  if (source->on_clone)
  {
    source->on_clone(new_clone, source);
  }

  return new_clone;
}

void *memcached_get_user_data(const memcached_st *ptr)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  return ptr->user_data;
}

void *memcached_set_user_data(memcached_st *ptr, void *data)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  void *ret= ptr->user_data;
  ptr->user_data= data;

  return ret;
}

memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
{
  return memcached_instance_push(destination, (org::libmemcached::Instance*)source->servers, source->number_of_hosts);
}

org::libmemcached::Instance* memcached_instance_fetch(memcached_st *ptr, uint32_t server_key)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  return &ptr->servers[server_key];
}

memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  return &ptr->servers[server_key];
}

org::libmemcached::Instance* memcached_instance_by_position(const memcached_st *ptr, uint32_t server_key)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  return &ptr->servers[server_key];
}

uint64_t memcached_query_id(const memcached_st *self)
{
  if (self == NULL)
  {
    return 0;
  }

  return self->query_id;
}

org::libmemcached::Instance* memcached_instance_list(const memcached_st *self)
{
  if (self)
  {
    return (org::libmemcached::Instance*)self->servers;
  }

  return NULL;
}

<commit_msg>Correctly copy and free memcached_st objects<commit_after>/*  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 *
 *  Libmemcached library
 *
 *  Copyright (C) 2011 Data Differential, http://datadifferential.com/
 *  Copyright (C) 2006-2009 Brian Aker All rights reserved.
 *
 *  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.
 *
 *      * The names of its contributors may not 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.
 *
 */

#include <libmemcached/common.h>

#include <libmemcached/options.hpp>
#include <libmemcached/virtual_bucket.h>

static inline bool _memcached_init(memcached_st *self)
{
  self->state.is_purging= false;
  self->state.is_processing_input= false;
  self->state.is_time_for_rebuild= false;

  self->flags.auto_eject_hosts= false;
  self->flags.binary_protocol= false;
  self->flags.buffer_requests= false;
  self->flags.hash_with_namespace= false;
  self->flags.no_block= false;
  self->flags.reply= true;
  self->flags.randomize_replica_read= false;
  self->flags.support_cas= false;
  self->flags.tcp_nodelay= false;
  self->flags.use_sort_hosts= false;
  self->flags.use_udp= false;
  self->flags.verify_key= false;
  self->flags.tcp_keepalive= false;
  self->flags.is_aes= false;
  self->flags.is_fetching_version= false;

  self->virtual_bucket= NULL;

  self->distribution= MEMCACHED_DISTRIBUTION_MODULA;

  if (hashkit_create(&self->hashkit) == NULL)
  {
    return false;
  }

  self->server_info.version= 0;

  self->ketama.continuum= NULL;
  self->ketama.continuum_count= 0;
  self->ketama.continuum_points_counter= 0;
  self->ketama.next_distribution_rebuild= 0;
  self->ketama.weighted_= false;

  self->number_of_hosts= 0;
  self->servers= NULL;
  self->last_disconnected_server= NULL;

  self->snd_timeout= 0;
  self->rcv_timeout= 0;
  self->server_failure_limit= MEMCACHED_SERVER_FAILURE_LIMIT;
  self->query_id= 1; // 0 is considered invalid

  /* TODO, Document why we picked these defaults */
  self->io_msg_watermark= 500;
  self->io_bytes_watermark= 65 * 1024;

  self->tcp_keepidle= 0;

  self->io_key_prefetch= 0;
  self->poll_timeout= MEMCACHED_DEFAULT_TIMEOUT;
  self->connect_timeout= MEMCACHED_DEFAULT_CONNECT_TIMEOUT;
  self->retry_timeout= MEMCACHED_SERVER_FAILURE_RETRY_TIMEOUT;
  self->dead_timeout= MEMCACHED_SERVER_FAILURE_DEAD_TIMEOUT;

  self->send_size= -1;
  self->recv_size= -1;

  self->user_data= NULL;
  self->number_of_replicas= 0;

  self->allocators= memcached_allocators_return_default();

  self->on_clone= NULL;
  self->on_cleanup= NULL;
  self->get_key_failure= NULL;
  self->delete_trigger= NULL;
  self->callbacks= NULL;
  self->sasl.callbacks= NULL;
  self->sasl.is_allocated= false;

  self->error_messages= NULL;
  self->_namespace= NULL;
  self->configure.initial_pool_size= 1;
  self->configure.max_pool_size= 1;
  self->configure.version= -1;
  self->configure.filename= NULL;
  self->configure.source_address= NULL;

  return true;
}

static void __memcached_free(memcached_st *ptr, bool release_st)
{
  /* If we have anything open, lets close it now */
  send_quit(ptr);
  memcached_instance_list_free(memcached_instance_list(ptr), memcached_instance_list_count(ptr));
  memcached_result_free(&ptr->result);

  memcached_virtual_bucket_free(ptr);

  memcached_instance_free((org::libmemcached::Instance*)ptr->last_disconnected_server);

  if (ptr->on_cleanup)
  {
    ptr->on_cleanup(ptr);
  }

  libmemcached_free(ptr, ptr->ketama.continuum);

  memcached_array_free(ptr->_namespace);
  ptr->_namespace= NULL;

  memcached_error_free(*ptr);

  if (LIBMEMCACHED_WITH_SASL_SUPPORT and ptr->sasl.callbacks)
  {
    memcached_destroy_sasl_auth_data(ptr);
  }

  if (release_st)
  {
    memcached_array_free(ptr->configure.filename);
    ptr->configure.filename= NULL;

    memcached_array_free(ptr->configure.source_address);
    ptr->configure.source_address= NULL;
  }

  hashkit_free(&ptr->hashkit);

  if (memcached_is_allocated(ptr) and release_st)
  {
    libmemcached_free(ptr, ptr);
  }
}

memcached_st *memcached_create(memcached_st *ptr)
{
  if (ptr)
  {
    ptr->options.is_allocated= false;
  }
  else
  {
    ptr= (memcached_st *)libmemcached_xmalloc(NULL, memcached_st);

    if (ptr == NULL)
    {
      return NULL; /*  MEMCACHED_MEMORY_ALLOCATION_FAILURE */
    }

    ptr->options.is_allocated= true;
  }

  if (_memcached_init(ptr) == false)
  {
    memcached_free(ptr);
    return NULL;
  }

  if (memcached_result_create(ptr, &ptr->result) == NULL)
  {
    memcached_free(ptr);
    return NULL;
  }

  WATCHPOINT_ASSERT_INITIALIZED(&ptr->result);

  return ptr;
}

memcached_st *memcached(const char *string, size_t length)
{
  if (length == 0 and string)
  {
    return NULL;
  }

  if (length and string == NULL)
  {
    return NULL;
  }

  if (length == 0)
  {
    if (bool(getenv("LIBMEMCACHED")))
    {
      string= getenv("LIBMEMCACHED");
      length= string ? strlen(string) : 0;
    }
  }

  memcached_st *memc= memcached_create(NULL);
  if (memc == NULL)
  {
    return NULL;
  }

  if (length == 0 or string == NULL)
  {
    return memc;
  }

  memcached_return_t rc= memcached_parse_configuration(memc, string, length);
  if (memcached_success(rc) and memcached_parse_filename(memc))
  {
    rc= memcached_parse_configure_file(*memc, memcached_parse_filename(memc), memcached_parse_filename_length(memc));
  }

  if (memcached_failed(rc))
  {
    memcached_free(memc);
    return NULL;
  }

  return memc;
}

memcached_return_t memcached_reset(memcached_st *ptr)
{
  WATCHPOINT_ASSERT(ptr);
  if (ptr == NULL)
  {
    return MEMCACHED_INVALID_ARGUMENTS;
  }

  bool stored_is_allocated= memcached_is_allocated(ptr);
  uint64_t query_id= ptr->query_id;
  __memcached_free(ptr, false);
  memcached_create(ptr);
  memcached_set_allocated(ptr, stored_is_allocated);
  ptr->query_id= query_id;

  if (ptr->configure.filename)
  {
    return memcached_parse_configure_file(*ptr, memcached_param_array(ptr->configure.filename));
  }

  return MEMCACHED_SUCCESS;
}

void memcached_servers_reset(memcached_st *self)
{
  if (self)
  {
    memcached_instance_list_free(memcached_instance_list(self), self->number_of_hosts);

    memcached_instance_set(self, NULL);
    self->number_of_hosts= 0;
    memcached_instance_free((org::libmemcached::Instance*)self->last_disconnected_server);
    self->last_disconnected_server= NULL;
  }
}

void memcached_reset_last_disconnected_server(memcached_st *self)
{
  if (self)
  {
    memcached_instance_free((org::libmemcached::Instance*)self->last_disconnected_server);
    self->last_disconnected_server= NULL;
  }
}

void memcached_free(memcached_st *ptr)
{
  if (ptr)
  {
    __memcached_free(ptr, true);
  }
}

/*
  clone is the destination, while source is the structure to clone.
  If source is NULL the call is the same as if a memcached_create() was
  called.
*/
memcached_st *memcached_clone(memcached_st *clone, const memcached_st *source)
{
  if (source == NULL)
  {
    return memcached_create(clone);
  }

  if (clone and memcached_is_allocated(clone))
  {
    return NULL;
  }

  memcached_st *new_clone= memcached_create(clone);

  if (new_clone == NULL)
  {
    return NULL;
  }

  new_clone->flags= source->flags;
  new_clone->send_size= source->send_size;
  new_clone->recv_size= source->recv_size;
  new_clone->poll_timeout= source->poll_timeout;
  new_clone->connect_timeout= source->connect_timeout;
  new_clone->retry_timeout= source->retry_timeout;
  new_clone->dead_timeout= source->dead_timeout;
  new_clone->distribution= source->distribution;

  if (hashkit_clone(&new_clone->hashkit, &source->hashkit) == NULL)
  {
    memcached_free(new_clone);
    return NULL;
  }

  new_clone->user_data= source->user_data;

  new_clone->snd_timeout= source->snd_timeout;
  new_clone->rcv_timeout= source->rcv_timeout;

  new_clone->on_clone= source->on_clone;
  new_clone->on_cleanup= source->on_cleanup;

  new_clone->allocators= source->allocators;

  new_clone->get_key_failure= source->get_key_failure;
  new_clone->delete_trigger= source->delete_trigger;
  new_clone->server_failure_limit= source->server_failure_limit;
  new_clone->io_msg_watermark= source->io_msg_watermark;
  new_clone->io_bytes_watermark= source->io_bytes_watermark;
  new_clone->io_key_prefetch= source->io_key_prefetch;
  new_clone->number_of_replicas= source->number_of_replicas;
  new_clone->tcp_keepidle= source->tcp_keepidle;

  if (memcached_server_count(source))
  {
    if (memcached_failed(memcached_push(new_clone, source)))
    {
      return NULL;
    }
  }

  new_clone->_namespace= memcached_array_clone(new_clone, source->_namespace);
  new_clone->configure.filename= memcached_array_clone(new_clone, source->configure.filename);
  new_clone->configure.source_address= memcached_array_clone(new_clone, source->configure.source_address);
  new_clone->configure.version= source->configure.version;

  if (LIBMEMCACHED_WITH_SASL_SUPPORT and source->sasl.callbacks)
  {
    if (memcached_failed(memcached_clone_sasl(new_clone, source)))
    {
      memcached_free(new_clone);
      return NULL;
    }
  }

  if (memcached_failed(run_distribution(new_clone)))
  {
    memcached_free(new_clone);

    return NULL;
  }

  if (source->on_clone)
  {
    source->on_clone(new_clone, source);
  }

  return new_clone;
}

void *memcached_get_user_data(const memcached_st *ptr)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  return ptr->user_data;
}

void *memcached_set_user_data(memcached_st *ptr, void *data)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  void *ret= ptr->user_data;
  ptr->user_data= data;

  return ret;
}

memcached_return_t memcached_push(memcached_st *destination, const memcached_st *source)
{
  return memcached_instance_push(destination, (org::libmemcached::Instance*)source->servers, source->number_of_hosts);
}

org::libmemcached::Instance* memcached_instance_fetch(memcached_st *ptr, uint32_t server_key)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  return &ptr->servers[server_key];
}

memcached_server_instance_st memcached_server_instance_by_position(const memcached_st *ptr, uint32_t server_key)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  return &ptr->servers[server_key];
}

org::libmemcached::Instance* memcached_instance_by_position(const memcached_st *ptr, uint32_t server_key)
{
  if (ptr == NULL)
  {
    return NULL;
  }

  return &ptr->servers[server_key];
}

uint64_t memcached_query_id(const memcached_st *self)
{
  if (self == NULL)
  {
    return 0;
  }

  return self->query_id;
}

org::libmemcached::Instance* memcached_instance_list(const memcached_st *self)
{
  if (self)
  {
    return (org::libmemcached::Instance*)self->servers;
  }

  return NULL;
}

<|endoftext|>