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

#ifdef __cplusplus
extern "C" {
#endif
#include "assert.h"
#include "em_core.h"
#include "em_usart.h"
#include "sl_board_control.h"
#include "sl_uartdrv_instances.h"
#ifdef EFR32MG24
#include "sl_uartdrv_eusart_vcom_config.h"
#else
#include "sl_uartdrv_usart_vcom_config.h"
#endif // EFR32MG24
#include "uart.h"
#include "uartdrv.h"
#include <stddef.h>
#include <string.h>

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#include "sl_power_manager.h"
#endif

#if !defined(MIN)
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#endif

#define HELPER1(x) USART##x##_RX_IRQn
#define HELPER2(x) HELPER1(x)

#define HELPER3(x) USART##x##_RX_IRQHandler
#define HELPER4(x) HELPER3(x)

// On MG24 boards VCOM runs on the EUSART device, MG12 uses the UART device
#ifdef EFR32MG24
#define USART_IRQ HELPER2(SL_UARTDRV_EUSART_VCOM_PERIPHERAL_NO)
#define USART_IRQHandler HELPER4(SL_UARTDRV_EUSART_VCOM_PERIPHERAL_NO)
#define vcom_handle sl_uartdrv_eusart_vcom_handle

#else
#define USART_IRQ HELPER2(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO)
#define USART_IRQHandler HELPER4(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO)
#define vcom_handle sl_uartdrv_usart_vcom_handle
#endif // EFR32MG24

typedef struct
{
    // The data buffer
    uint8_t * pBuffer;
    // The offset of the first item written to the list.
    volatile uint16_t Head;
    // The offset of the next item to be written to the list.
    volatile uint16_t Tail;
    // Maxium size of data that can be hold in buffer before overwriting
    uint16_t MaxSize;
} Fifo_t;

#define UART_CONSOLE_ERR -1 // Negative value in case of UART Console action failed. Triggers a failure for PW_RPC
#define MAX_BUFFER_SIZE 256
#define MAX_DMA_BUFFER_SIZE (MAX_BUFFER_SIZE / 2)
// In order to reduce the probability of data loss during the dmaFull callback handler we use
// two duplicate receive buffers so we can always have one "active" receive queue.
static uint8_t sRxDmaBuffer[MAX_DMA_BUFFER_SIZE];
static uint8_t sRxDmaBuffer2[MAX_DMA_BUFFER_SIZE];
static uint16_t lastCount; // Nb of bytes already processed from the active dmaBuffer

// Rx buffer for the receive Fifo
static uint8_t sRxFifoBuffer[MAX_BUFFER_SIZE];
static Fifo_t sReceiveFifo;

static void UART_rx_callback(UARTDRV_Handle_t handle, Ecode_t transferStatus, uint8_t * data, UARTDRV_Count_t transferCount);

static bool InitFifo(Fifo_t * fifo, uint8_t * pDataBuffer, uint16_t bufferSize)
{
    if (fifo == NULL || pDataBuffer == NULL)
    {
        return false;
    }

    fifo->pBuffer = pDataBuffer;
    fifo->MaxSize = bufferSize;
    fifo->Tail = fifo->Head = 0;

    return true;
}

/*
 *   @brief Get the amount of unprocessed bytes in the fifo buffer
 *   @param Ptr to the fifo
 *   @return Nb of "unread" bytes available in the fifo
 */
static uint16_t AvailableDataCount(Fifo_t * fifo)
{
    uint16_t size = 0;

    // if equal there is no data return 0 directly
    if (fifo->Tail != fifo->Head)
    {
        // determine if a wrap around occurred to get the right data size avalaible.
        size = (fifo->Tail < fifo->Head) ? (fifo->MaxSize - fifo->Head + fifo->Tail) : (fifo->Tail - fifo->Head);
    }

    return size;
}

/*
 *   @brief Get the available space in the fifo buffer to insert new data
 *   @param Ptr to the fifo
 *   @return Nb of free bytes left in te buffer
 */
static uint16_t RemainingSpace(Fifo_t * fifo)
{
    return fifo->MaxSize - AvailableDataCount(fifo);
}

/*
 *   @brief Write data in the fifo as a circular buffer
 *   @param Ptr to the fifo, ptr of the data to write, nb of bytes to write
 */
static void WriteToFifo(Fifo_t * fifo, uint8_t * pDataToWrite, uint16_t SizeToWrite)
{
    assert(fifo);
    assert(pDataToWrite);
    assert(SizeToWrite <= fifo->MaxSize);

    // Overwrite is not allowed
    if (RemainingSpace(fifo) >= SizeToWrite)
    {
        uint16_t nBytesBeforWrap = (fifo->MaxSize - fifo->Tail);
        if (SizeToWrite > nBytesBeforWrap)
        {
            // The number of bytes to write is bigger than the remaining bytes
            // in the buffer, we have to wrap around
            memcpy(fifo->pBuffer + fifo->Tail, pDataToWrite, nBytesBeforWrap);
            memcpy(fifo->pBuffer, pDataToWrite + nBytesBeforWrap, SizeToWrite - nBytesBeforWrap);
        }
        else
        {
            memcpy(fifo->pBuffer + fifo->Tail, pDataToWrite, SizeToWrite);
        }

        fifo->Tail = (fifo->Tail + SizeToWrite) % fifo->MaxSize; // increment tail with wraparound
    }
}

/*
 *   @brief Write data in the fifo as a circular buffer
 *   @param Ptr to the fifo, ptr to contain the data to process, nb of bytes to pull from the fifo
 *   @return Nb of bytes that were retrieved.
 */
static uint8_t RetrieveFromFifo(Fifo_t * fifo, uint8_t * pData, uint16_t SizeToRead)
{
    assert(fifo);
    assert(pData);
    assert(SizeToRead <= fifo->MaxSize);

    uint16_t ReadSize        = MIN(SizeToRead, AvailableDataCount(fifo));
    uint16_t nBytesBeforWrap = (fifo->MaxSize - fifo->Head);

    if (ReadSize > nBytesBeforWrap)
    {
        memcpy(pData, fifo->pBuffer + fifo->Head, nBytesBeforWrap);
        memcpy(pData + nBytesBeforWrap, fifo->pBuffer, ReadSize - nBytesBeforWrap);
    }
    else
    {
        memcpy(pData, (fifo->pBuffer + fifo->Head), ReadSize);
    }

    fifo->Head = (fifo->Head + ReadSize) % fifo->MaxSize; // increment tail with wraparound

    return ReadSize;
}

/*
 *   @brief Init the the UART for serial communication, Start DMA reception
 *          and init Fifo to handle the received data from this uart
 *
 *   @Note This UART is used for pigweed rpc
 */
void uartConsoleInit(void)
{
    sl_board_enable_vcom();
    // Init a fifo for the data received on the uart
    InitFifo(&sReceiveFifo, sRxFifoBuffer, MAX_BUFFER_SIZE);

    // Activate 2 dma queues to always have one active

    UARTDRV_Receive(vcom_handle, sRxDmaBuffer, MAX_DMA_BUFFER_SIZE, UART_rx_callback);
    UARTDRV_Receive(vcom_handle, sRxDmaBuffer2, MAX_DMA_BUFFER_SIZE, UART_rx_callback);

    // Enable USART0 interrupt to wake OT task when data arrives
    NVIC_ClearPendingIRQ(USART_IRQ);
    NVIC_EnableIRQ(USART_IRQ);

#ifdef EFR32MG24
    EUSART_IntEnable(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, USART_IF_RXDATAV);
#else
    USART_IntEnable(SL_UARTDRV_USART_VCOM_PERIPHERAL, USART_IF_RXDATAV);
#endif // EFR32MG24
}

void USART_IRQHandler(void)
{
#ifdef ENABLE_CHIP_SHELL
    chip::NotifyShellProcessFromISR();
#endif
#if defined(SL_WIFI)
    /* TODO */
#elif !defined(PW_RPC_ENABLED)
    otSysEventSignalPending();
#endif
}

/*
 *   @brief Callback triggered when a UARTDRV DMA buffer is full
 */
static void UART_rx_callback(UARTDRV_Handle_t handle, Ecode_t transferStatus, uint8_t * data, UARTDRV_Count_t transferCount)
{
    (void) transferStatus;

    uint8_t writeSize = (transferCount - lastCount);
    if (RemainingSpace(&sReceiveFifo) >= writeSize)
    {
        WriteToFifo(&sReceiveFifo, data + lastCount, writeSize);
        lastCount = 0;
    }

    UARTDRV_Receive(vcom_handle, data, transferCount, UART_rx_callback);

#ifdef ENABLE_CHIP_SHELL
    chip::NotifyShellProcessFromISR();
#endif
#if defined(SL_WIFI)
    /* TODO */
#elif !defined(PW_RPC_ENABLED)
    otSysEventSignalPending();
#endif
}

/*
 *   @brief Read the data available from the console Uart
 *   @param Buffer that contains the data to write, number bytes to write.
 *   @return Amount of bytes written or ERROR (-1)
 */
int16_t uartConsoleWrite(const char * Buf, uint16_t BufLength)
{
    if (Buf == NULL || BufLength < 1)
    {
        return UART_CONSOLE_ERR;
    }

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
    sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
#endif

    // Use of ForceTransmit here. Transmit with DMA was causing errors with PW_RPC
    // TODO Use DMA and find/fix what causes the issue with PW
    if (UARTDRV_ForceTransmit(vcom_handle, (uint8_t *) Buf, BufLength) == ECODE_EMDRV_UARTDRV_OK)
    {
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
        sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
#endif
        return BufLength;
    }

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
    sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
#endif

    return UART_CONSOLE_ERR;
}

/*
 *   @brief Read the data available from the console Uart
 *   @param Buffer for the data to be read, number bytes to read.
 *   @return Amount of bytes that was read from the rx fifo or ERROR (-1)
 */
int16_t uartConsoleRead(char * Buf, uint16_t NbBytesToRead)
{
    uint8_t * data;
    UARTDRV_Count_t count, remaining;

    if (Buf == NULL || NbBytesToRead < 1)
    {
        return UART_CONSOLE_ERR;
    }

    if (NbBytesToRead > AvailableDataCount(&sReceiveFifo))
    {
        // Not enough data available in the fifo for the read size request
        // If there is data available in dma buffer, get it now.
        CORE_ATOMIC_SECTION(UARTDRV_GetReceiveStatus(vcom_handle, &data, &count, &remaining); if (count > lastCount) {
            WriteToFifo(&sReceiveFifo, data + lastCount, count - lastCount);
            lastCount = count;
        })
    }

    return (int16_t) RetrieveFromFifo(&sReceiveFifo, (uint8_t *) Buf, NbBytesToRead);
}

#ifdef __cplusplus
}
#endif
<commit_msg>[EFR32] Fix OpenThread and Matter shell operation on EFRMG24 boards (#19858)<commit_after>/*
 *
 *    Copyright (c) 2021 Project CHIP Authors
 *    All rights reserved.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *        http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */
#include "AppConfig.h"
#include "matter_shell.h"

#ifdef __cplusplus
extern "C" {
#endif
#include "assert.h"
#include "em_core.h"
#include "em_usart.h"
#include "sl_board_control.h"
#include "sl_uartdrv_instances.h"
#ifdef EFR32MG24
#include "sl_uartdrv_eusart_vcom_config.h"
#else
#include "sl_uartdrv_usart_vcom_config.h"
#endif // EFR32MG24
#include "uart.h"
#include "uartdrv.h"
#include <stddef.h>
#include <string.h>

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
#include "sl_power_manager.h"
#endif

#if !defined(MIN)
#define MIN(A, B) ((A) < (B) ? (A) : (B))
#endif

#ifdef EFR32MG24
#define HELPER1(x) EUSART##x##_RX_IRQn
#else
#define HELPER1(x) USART##x##_RX_IRQn
#endif

#define HELPER2(x) HELPER1(x)

#ifdef EFR32MG24
#define HELPER3(x) EUSART##x##_RX_IRQHandler
#else
#define HELPER3(x) USART##x##_RX_IRQHandler
#endif

#define HELPER4(x) HELPER3(x)

// On MG24 boards VCOM runs on the EUSART device, MG12 uses the UART device
#ifdef EFR32MG24
#define USART_IRQ HELPER2(SL_UARTDRV_EUSART_VCOM_PERIPHERAL_NO)
#define USART_IRQHandler HELPER4(SL_UARTDRV_EUSART_VCOM_PERIPHERAL_NO)
#define vcom_handle sl_uartdrv_eusart_vcom_handle
#else
#define USART_IRQ HELPER2(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO)
#define USART_IRQHandler HELPER4(SL_UARTDRV_USART_VCOM_PERIPHERAL_NO)
#define vcom_handle sl_uartdrv_usart_vcom_handle
#endif // EFR32MG24

typedef struct
{
    // The data buffer
    uint8_t * pBuffer;
    // The offset of the first item written to the list.
    volatile uint16_t Head;
    // The offset of the next item to be written to the list.
    volatile uint16_t Tail;
    // Maxium size of data that can be hold in buffer before overwriting
    uint16_t MaxSize;
} Fifo_t;

#define UART_CONSOLE_ERR -1 // Negative value in case of UART Console action failed. Triggers a failure for PW_RPC
#define MAX_BUFFER_SIZE 256
#define MAX_DMA_BUFFER_SIZE (MAX_BUFFER_SIZE / 2)
// In order to reduce the probability of data loss during the dmaFull callback handler we use
// two duplicate receive buffers so we can always have one "active" receive queue.
static uint8_t sRxDmaBuffer[MAX_DMA_BUFFER_SIZE];
static uint8_t sRxDmaBuffer2[MAX_DMA_BUFFER_SIZE];
static uint16_t lastCount; // Nb of bytes already processed from the active dmaBuffer

// Rx buffer for the receive Fifo
static uint8_t sRxFifoBuffer[MAX_BUFFER_SIZE];
static Fifo_t sReceiveFifo;

static void UART_rx_callback(UARTDRV_Handle_t handle, Ecode_t transferStatus, uint8_t * data, UARTDRV_Count_t transferCount);

static bool InitFifo(Fifo_t * fifo, uint8_t * pDataBuffer, uint16_t bufferSize)
{
    if (fifo == NULL || pDataBuffer == NULL)
    {
        return false;
    }

    fifo->pBuffer = pDataBuffer;
    fifo->MaxSize = bufferSize;
    fifo->Tail = fifo->Head = 0;

    return true;
}

/*
 *   @brief Get the amount of unprocessed bytes in the fifo buffer
 *   @param Ptr to the fifo
 *   @return Nb of "unread" bytes available in the fifo
 */
static uint16_t AvailableDataCount(Fifo_t * fifo)
{
    uint16_t size = 0;

    // if equal there is no data return 0 directly
    if (fifo->Tail != fifo->Head)
    {
        // determine if a wrap around occurred to get the right data size avalaible.
        size = (fifo->Tail < fifo->Head) ? (fifo->MaxSize - fifo->Head + fifo->Tail) : (fifo->Tail - fifo->Head);
    }

    return size;
}

/*
 *   @brief Get the available space in the fifo buffer to insert new data
 *   @param Ptr to the fifo
 *   @return Nb of free bytes left in te buffer
 */
static uint16_t RemainingSpace(Fifo_t * fifo)
{
    return fifo->MaxSize - AvailableDataCount(fifo);
}

/*
 *   @brief Write data in the fifo as a circular buffer
 *   @param Ptr to the fifo, ptr of the data to write, nb of bytes to write
 */
static void WriteToFifo(Fifo_t * fifo, uint8_t * pDataToWrite, uint16_t SizeToWrite)
{
    assert(fifo);
    assert(pDataToWrite);
    assert(SizeToWrite <= fifo->MaxSize);

    // Overwrite is not allowed
    if (RemainingSpace(fifo) >= SizeToWrite)
    {
        uint16_t nBytesBeforWrap = (fifo->MaxSize - fifo->Tail);
        if (SizeToWrite > nBytesBeforWrap)
        {
            // The number of bytes to write is bigger than the remaining bytes
            // in the buffer, we have to wrap around
            memcpy(fifo->pBuffer + fifo->Tail, pDataToWrite, nBytesBeforWrap);
            memcpy(fifo->pBuffer, pDataToWrite + nBytesBeforWrap, SizeToWrite - nBytesBeforWrap);
        }
        else
        {
            memcpy(fifo->pBuffer + fifo->Tail, pDataToWrite, SizeToWrite);
        }

        fifo->Tail = (fifo->Tail + SizeToWrite) % fifo->MaxSize; // increment tail with wraparound
    }
}

/*
 *   @brief Write data in the fifo as a circular buffer
 *   @param Ptr to the fifo, ptr to contain the data to process, nb of bytes to pull from the fifo
 *   @return Nb of bytes that were retrieved.
 */
static uint8_t RetrieveFromFifo(Fifo_t * fifo, uint8_t * pData, uint16_t SizeToRead)
{
    assert(fifo);
    assert(pData);
    assert(SizeToRead <= fifo->MaxSize);

    uint16_t ReadSize        = MIN(SizeToRead, AvailableDataCount(fifo));
    uint16_t nBytesBeforWrap = (fifo->MaxSize - fifo->Head);

    if (ReadSize > nBytesBeforWrap)
    {
        memcpy(pData, fifo->pBuffer + fifo->Head, nBytesBeforWrap);
        memcpy(pData + nBytesBeforWrap, fifo->pBuffer, ReadSize - nBytesBeforWrap);
    }
    else
    {
        memcpy(pData, (fifo->pBuffer + fifo->Head), ReadSize);
    }

    fifo->Head = (fifo->Head + ReadSize) % fifo->MaxSize; // increment tail with wraparound

    return ReadSize;
}

/*
 *   @brief Init the the UART for serial communication, Start DMA reception
 *          and init Fifo to handle the received data from this uart
 *
 *   @Note This UART is used for pigweed rpc
 */
void uartConsoleInit(void)
{
    sl_board_enable_vcom();
    // Init a fifo for the data received on the uart
    InitFifo(&sReceiveFifo, sRxFifoBuffer, MAX_BUFFER_SIZE);

    // Activate 2 dma queues to always have one active

    UARTDRV_Receive(vcom_handle, sRxDmaBuffer, MAX_DMA_BUFFER_SIZE, UART_rx_callback);
    UARTDRV_Receive(vcom_handle, sRxDmaBuffer2, MAX_DMA_BUFFER_SIZE, UART_rx_callback);

    // Enable USART0/EUSART0 interrupt to wake OT task when data arrives
    NVIC_ClearPendingIRQ(USART_IRQ);
    NVIC_EnableIRQ(USART_IRQ);

#ifdef EFR32MG24
    // Clear previous RX interrupts
    EUSART_IntClear(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL);

    // Enable RX interrupts
    EUSART_IntEnable(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL);

    // Enable EUSART
    EUSART_Enable(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, eusartEnable);
#else
    USART_IntEnable(SL_UARTDRV_USART_VCOM_PERIPHERAL, USART_IF_RXDATAV);
#endif // EFR32MG24
}

void USART_IRQHandler(void)
{
#ifdef ENABLE_CHIP_SHELL
    chip::NotifyShellProcessFromISR();
#endif
#if defined(SL_WIFI)
    /* TODO */
#elif !defined(PW_RPC_ENABLED)
    otSysEventSignalPending();
#endif

#ifdef EFR32MG24
    EUSART_IntClear(SL_UARTDRV_EUSART_VCOM_PERIPHERAL, EUSART_IF_RXFL);
#endif
}

/*
 *   @brief Callback triggered when a UARTDRV DMA buffer is full
 */
static void UART_rx_callback(UARTDRV_Handle_t handle, Ecode_t transferStatus, uint8_t * data, UARTDRV_Count_t transferCount)
{
    (void) transferStatus;

    uint8_t writeSize = (transferCount - lastCount);
    if (RemainingSpace(&sReceiveFifo) >= writeSize)
    {
        WriteToFifo(&sReceiveFifo, data + lastCount, writeSize);
        lastCount = 0;
    }

    UARTDRV_Receive(vcom_handle, data, transferCount, UART_rx_callback);

#ifdef ENABLE_CHIP_SHELL
    chip::NotifyShellProcessFromISR();
#endif
#if defined(SL_WIFI)
    /* TODO */
#elif !defined(PW_RPC_ENABLED)
    otSysEventSignalPending();
#endif
}

/*
 *   @brief Read the data available from the console Uart
 *   @param Buffer that contains the data to write, number bytes to write.
 *   @return Amount of bytes written or ERROR (-1)
 */
int16_t uartConsoleWrite(const char * Buf, uint16_t BufLength)
{
    if (Buf == NULL || BufLength < 1)
    {
        return UART_CONSOLE_ERR;
    }

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
    sl_power_manager_add_em_requirement(SL_POWER_MANAGER_EM1);
#endif

    // Use of ForceTransmit here. Transmit with DMA was causing errors with PW_RPC
    // TODO Use DMA and find/fix what causes the issue with PW
    if (UARTDRV_ForceTransmit(vcom_handle, (uint8_t *) Buf, BufLength) == ECODE_EMDRV_UARTDRV_OK)
    {
#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
        sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
#endif
        return BufLength;
    }

#if defined(SL_CATALOG_POWER_MANAGER_PRESENT)
    sl_power_manager_remove_em_requirement(SL_POWER_MANAGER_EM1);
#endif

    return UART_CONSOLE_ERR;
}

/*
 *   @brief Read the data available from the console Uart
 *   @param Buffer for the data to be read, number bytes to read.
 *   @return Amount of bytes that was read from the rx fifo or ERROR (-1)
 */
int16_t uartConsoleRead(char * Buf, uint16_t NbBytesToRead)
{
    uint8_t * data;
    UARTDRV_Count_t count, remaining;

    if (Buf == NULL || NbBytesToRead < 1)
    {
        return UART_CONSOLE_ERR;
    }

    if (NbBytesToRead > AvailableDataCount(&sReceiveFifo))
    {
        // Not enough data available in the fifo for the read size request
        // If there is data available in dma buffer, get it now.
        CORE_ATOMIC_SECTION(UARTDRV_GetReceiveStatus(vcom_handle, &data, &count, &remaining); if (count > lastCount) {
            WriteToFifo(&sReceiveFifo, data + lastCount, count - lastCount);
            lastCount = count;
        })
    }

    return (int16_t) RetrieveFromFifo(&sReceiveFifo, (uint8_t *) Buf, NbBytesToRead);
}

#ifdef __cplusplus
}
#endif
<|endoftext|>


<commit_before>/*
This file is part of CanFestival, a library implementing CanOpen Stack.

Copyright (C): Edouard TISSERANT and Francis DUPIN
Copyright (C) Win32 Port Leonid Tochinski

See COPYING file for copyrights details.

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

This 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
*/

/*
 CAN driver interface.
*/

#include <windows.h>

extern "C"
   {
#define DLL_CALL(funcname) (*_##funcname)
#define FCT_PTR_INIT =NULL
#include "canfestival.h"
#include "timer.h"

#include "timers_driver.h"
   };

typedef UNS8 (*CANRECEIVE_DRIVER_PROC)(void* inst, Message *m);
typedef UNS8 (*CANSEND_DRIVER_PROC)(void* inst, const Message *m);
typedef void* (*CANOPEN_DRIVER_PROC)(s_BOARD *board);
typedef int (*CANCLOSE_DRIVER_PROC)(void* inst);

class driver_procs
   {
   public:
      driver_procs();
      ~driver_procs();

      HMODULE load_canfestival_driver(LPCTSTR driver_name);
      bool can_driver_valid() const;

   public:
      // can driver
      CANRECEIVE_DRIVER_PROC m_canReceive;
      CANSEND_DRIVER_PROC m_canSend;
      CANOPEN_DRIVER_PROC m_canOpen;
      CANCLOSE_DRIVER_PROC m_canClose;

      // driver module habndle
      HMODULE m_driver_handle;
   };

driver_procs::driver_procs() : m_canReceive(0),
      m_canSend(0),
      m_canOpen(0),
      m_canClose(0),
      m_driver_handle(0)
   {}

driver_procs::~driver_procs()
   {
   if (m_driver_handle)
      ::FreeLibrary(m_driver_handle);
   }

bool driver_procs::can_driver_valid() const
   {
   return ((m_canReceive != NULL) &&
           (m_canSend != NULL) &&
           (m_canOpen != NULL) &&
           (m_canClose != NULL));
   }

// GetProcAddress doesn't have an UNICODE version for NT
#ifdef UNDER_CE
  #define myTEXT(str) TEXT(str)
#else
  #define myTEXT(str) str
#endif

HMODULE driver_procs::load_canfestival_driver(LPCTSTR driver_name)
   {
  //LPCTSTR driver1 = "C:\\msys\\1.0\\home\\Ontaide\\can\\CanFestival-3\\drivers\\can_peak_win32\\cygcan_peak_win32.dll";
  //LPCTSTR driver2 = "C:\\msys\\1.0\\home\\Ontaide\\can\\CanFestival-3\\drivers\\can_peak_win32\\cygcan_peak_win32.dll";
  //printf("can_driver_valid=%d\n",can_driver_valid());
   if (can_driver_valid())
      return m_driver_handle;
   printf("driver_name=%s\n",driver_name);
   m_driver_handle = ::LoadLibrary(driver_name);
   //printf("m_driver_handle=%d\n",m_driver_handle);
   //printf("testerror =%s\n",GetLastError());
   if (m_driver_handle == NULL)
      return NULL;

   m_canReceive = (CANRECEIVE_DRIVER_PROC)::GetProcAddress(m_driver_handle, myTEXT("canReceive_driver"));
   m_canSend = (CANSEND_DRIVER_PROC)::GetProcAddress(m_driver_handle, myTEXT("canSend_driver"));
   m_canOpen = (CANOPEN_DRIVER_PROC)::GetProcAddress(m_driver_handle, myTEXT("canOpen_driver"));
   m_canClose = (CANCLOSE_DRIVER_PROC)::GetProcAddress(m_driver_handle, myTEXT("canClose_driver"));
   return can_driver_valid()?m_driver_handle:NULL;
   }

struct driver_data
   {
   CO_Data * d;
   HANDLE receive_thread;
   void* inst;
   volatile bool continue_receive_thread;
   };

driver_procs s_driver_procs;

LIB_HANDLE LoadCanDriver(const char* driver_name)
   {
		return s_driver_procs.load_canfestival_driver((LPCTSTR)driver_name);
   }

UNS8 canReceive(CAN_PORT fd0, Message *m)
   {

   if (fd0 != NULL && s_driver_procs.m_canReceive != NULL)
	   {
		  driver_data* data = (driver_data*)fd0;
		  return (*s_driver_procs.m_canReceive)(data->inst, m);
	   }
   return 1;
   }

void* canReceiveLoop(CAN_PORT fd0)
   {
   driver_data* data = (driver_data*)fd0;
   Message m;
   while (data->continue_receive_thread)
      {
      if (!canReceive(fd0, &m))
         {
         EnterMutex();
         canDispatch(data->d, &m);
         LeaveMutex();
         }
      else
         {
		 break;
         ::Sleep(1);
         }
      }
   return 0;
   }

/***************************************************************************/
UNS8 canSend(CAN_PORT fd0, Message *m)
   {
   if (fd0 != NULL && s_driver_procs.m_canSend != NULL)
      {
      UNS8 res;
      driver_data* data = (driver_data*)fd0;
      res = (*s_driver_procs.m_canSend)(data->inst, m);
      if (res)
         return 1; // OK
      }
   return 0; // NOT OK
   }

/***************************************************************************/
CAN_HANDLE canOpen(s_BOARD *board, CO_Data * d)
   {
   if (board != NULL && s_driver_procs.m_canOpen != NULL)
      {
      void* inst = (*s_driver_procs.m_canOpen)(board);
      if (inst != NULL)
         {
         driver_data* data = new driver_data;
         data->d = d;
         data->inst = inst;
         data->continue_receive_thread = true;
         CreateReceiveTask(data, &data->receive_thread, (void*)&canReceiveLoop);
	 EnterMutex();
         d->canHandle = data;
         LeaveMutex();
         return data;
         }
      }
   return NULL;
   }

/***************************************************************************/
int canClose(CO_Data * d)
   {
   if (s_driver_procs.m_canClose != NULL)
      {
		  driver_data* data;
		  EnterMutex();
		  if(d->canHandle != NULL){
			data = (driver_data*)d->canHandle;
			d->canHandle = NULL;
			data->continue_receive_thread = false;}
		  LeaveMutex();
		  WaitReceiveTaskEnd(&data->receive_thread);
		  (*s_driver_procs.m_canClose)(data->inst);
		  delete data;
		  return 0;
      }
   return 0;
   }

<commit_msg>fix bug in canclose for win32<commit_after>/*
This file is part of CanFestival, a library implementing CanOpen Stack.

Copyright (C): Edouard TISSERANT and Francis DUPIN
Copyright (C) Win32 Port Leonid Tochinski

See COPYING file for copyrights details.

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

This 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
*/

/*
 CAN driver interface.
*/

#include <windows.h>

extern "C"
   {
#define DLL_CALL(funcname) (*_##funcname)
#define FCT_PTR_INIT =NULL
#include "canfestival.h"
#include "timer.h"

#include "timers_driver.h"
   };

typedef UNS8 (*CANRECEIVE_DRIVER_PROC)(void* inst, Message *m);
typedef UNS8 (*CANSEND_DRIVER_PROC)(void* inst, const Message *m);
typedef void* (*CANOPEN_DRIVER_PROC)(s_BOARD *board);
typedef int (*CANCLOSE_DRIVER_PROC)(void* inst);

class driver_procs
   {
   public:
      driver_procs();
      ~driver_procs();

      HMODULE load_canfestival_driver(LPCTSTR driver_name);
      bool can_driver_valid() const;

   public:
      // can driver
      CANRECEIVE_DRIVER_PROC m_canReceive;
      CANSEND_DRIVER_PROC m_canSend;
      CANOPEN_DRIVER_PROC m_canOpen;
      CANCLOSE_DRIVER_PROC m_canClose;

      // driver module habndle
      HMODULE m_driver_handle;
   };

driver_procs::driver_procs() : m_canReceive(0),
      m_canSend(0),
      m_canOpen(0),
      m_canClose(0),
      m_driver_handle(0)
   {}

driver_procs::~driver_procs()
   {
   if (m_driver_handle)
      ::FreeLibrary(m_driver_handle);
   }

bool driver_procs::can_driver_valid() const
   {
   return ((m_canReceive != NULL) &&
           (m_canSend != NULL) &&
           (m_canOpen != NULL) &&
           (m_canClose != NULL));
   }

// GetProcAddress doesn't have an UNICODE version for NT
#ifdef UNDER_CE
  #define myTEXT(str) TEXT(str)
#else
  #define myTEXT(str) str
#endif

HMODULE driver_procs::load_canfestival_driver(LPCTSTR driver_name)
   {
  //LPCTSTR driver1 = "C:\\msys\\1.0\\home\\Ontaide\\can\\CanFestival-3\\drivers\\can_peak_win32\\cygcan_peak_win32.dll";
  //LPCTSTR driver2 = "C:\\msys\\1.0\\home\\Ontaide\\can\\CanFestival-3\\drivers\\can_peak_win32\\cygcan_peak_win32.dll";
  //printf("can_driver_valid=%d\n",can_driver_valid());
   if (can_driver_valid())
      return m_driver_handle;
   printf("driver_name=%s\n",driver_name);
   m_driver_handle = ::LoadLibrary(driver_name);
   //printf("m_driver_handle=%d\n",m_driver_handle);
   //printf("testerror =%s\n",GetLastError());
   if (m_driver_handle == NULL)
      return NULL;

   m_canReceive = (CANRECEIVE_DRIVER_PROC)::GetProcAddress(m_driver_handle, myTEXT("canReceive_driver"));
   m_canSend = (CANSEND_DRIVER_PROC)::GetProcAddress(m_driver_handle, myTEXT("canSend_driver"));
   m_canOpen = (CANOPEN_DRIVER_PROC)::GetProcAddress(m_driver_handle, myTEXT("canOpen_driver"));
   m_canClose = (CANCLOSE_DRIVER_PROC)::GetProcAddress(m_driver_handle, myTEXT("canClose_driver"));
   return can_driver_valid()?m_driver_handle:NULL;
   }

struct driver_data
   {
   CO_Data * d;
   HANDLE receive_thread;
   void* inst;
   volatile bool continue_receive_thread;
   };

driver_procs s_driver_procs;

LIB_HANDLE LoadCanDriver(const char* driver_name)
   {
		return s_driver_procs.load_canfestival_driver((LPCTSTR)driver_name);
   }

UNS8 canReceive(CAN_PORT fd0, Message *m)
   {

   if (fd0 != NULL && s_driver_procs.m_canReceive != NULL)
	   {
		  driver_data* data = (driver_data*)fd0;
		  return (*s_driver_procs.m_canReceive)(data->inst, m);
	   }
   return 1;
   }

void* canReceiveLoop(CAN_PORT fd0)
   {
   driver_data* data = (driver_data*)fd0;
   Message m;
   while (data->continue_receive_thread)
      {
      if (!canReceive(fd0, &m))
         {
         EnterMutex();
         canDispatch(data->d, &m);
         LeaveMutex();
         }
      else
         {
		 break;
         ::Sleep(1);
         }
      }
   return 0;
   }

/***************************************************************************/
UNS8 canSend(CAN_PORT fd0, Message *m)
   {
   if (fd0 != NULL && s_driver_procs.m_canSend != NULL)
      {
      UNS8 res;
      driver_data* data = (driver_data*)fd0;
      res = (*s_driver_procs.m_canSend)(data->inst, m);
      if (res)
         return 1; // OK
      }
   return 0; // NOT OK
   }

/***************************************************************************/
CAN_HANDLE canOpen(s_BOARD *board, CO_Data * d)
   {
   if (board != NULL && s_driver_procs.m_canOpen != NULL)
      {
      void* inst = (*s_driver_procs.m_canOpen)(board);
      if (inst != NULL)
         {
         driver_data* data = new driver_data;
         data->d = d;
         data->inst = inst;
         data->continue_receive_thread = true;
         CreateReceiveTask(data, &data->receive_thread, (void*)&canReceiveLoop);
	 EnterMutex();
         d->canHandle = data;
         LeaveMutex();
         return data;
         }
      }
   return NULL;
   }

/***************************************************************************/
int canClose(CO_Data * d)
   {
   if (s_driver_procs.m_canClose != NULL)
      {
		  driver_data* data;
		  EnterMutex();
		  if(d->canHandle != NULL){
			data = (driver_data*)d->canHandle;
			d->canHandle = NULL;
			data->continue_receive_thread = false;}
		  LeaveMutex();
		  (*s_driver_procs.m_canClose)(data->inst);
		  WaitReceiveTaskEnd(&data->receive_thread);
		  delete data;
		  return 0;
      }
   return 0;
   }

<|endoftext|>


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

#include <iostream>

#include "node_dumper.h"
#include "node.h"

namespace ydsh {
namespace ast {

void NodeDumper::dump(const char *fieldName, const char *value) {
    std::string str(value);
    this->dump(fieldName, str);
}

void NodeDumper::dump(const char *fieldName, const std::string &value) {
    this->writeName(fieldName);

    this->stream << '"';
    for(char ch : value) {
        bool escape = true;
        switch(ch) {
        case '\t':
            ch = 't';
            break;
        case '\r':
            ch = 'r';
            break;
        case '\n':
            ch = 'n';
            break;
        case '"':
            ch = '"';
            break;
        case '\\':
            ch = '\\';
            break;
        default:
            escape = false;
            break;
        }
        if(escape) {
            this->stream << '\\';
        }
        this->stream << ch;
    }
    this->stream << '"' << std::endl;
}

void NodeDumper::dump(const char *fieldName, const std::vector<Node *> &nodes) {
    this->writeName(fieldName);
    this->stream << std::endl;

    this->enterIndent();
    for(Node *node : nodes) {
        this->indent();
        this->stream << "- ";
        this->dumpNodeHeader(*node, true);
        this->enterIndent();
        node->dump(*this);
        this->leaveIndent();
    }
    this->leaveIndent();
}

void NodeDumper::dump(const char *fieldName, const std::list<Node *> &nodes) {
    this->writeName(fieldName);
    this->stream << std::endl;

    this->enterIndent();
    for(Node *node : nodes) {
        this->indent();
        this->stream << "- ";
        this->dumpNodeHeader(*node, true);
        this->enterIndent();
        node->dump(*this);
        this->leaveIndent();
    }
    this->leaveIndent();
}

void NodeDumper::dump(const char *fieldName, const Node &node) {
    // write field name
    this->writeName(fieldName);

    // write node body
    this->stream << std::endl;
    this->enterIndent();
    this->dump(node);
    this->leaveIndent();
}

void NodeDumper::dump(const char *fieldName, const DSType &type) {
    this->writeName(fieldName);
    this->stream << this->pool.getTypeName(type) << std::endl;
}

void NodeDumper::dumpNull(const char *fieldName) {
    this->writeName(fieldName);
    this->stream << std::endl;
}

void NodeDumper::dump(const Node &node) {
    this->indent();
    this->dumpNodeHeader(node);
    node.dump(*this);
}

void NodeDumper::enterIndent() {
    this->indentLevel++;
}

void NodeDumper::leaveIndent() {
    this->indentLevel--;
}

void NodeDumper::indent() {
    for(unsigned int i = 0; i < this->indentLevel; i++) {
        this->stream << "  ";
    }
}

void NodeDumper::dumpNodeHeader(const Node &node, bool inArray) {
    std::string className = misc::Demangle()(typeid(node));

    this->stream << "<Node>: " << std::endl;
    this->enterIndent();
    if(inArray) {
        this->enterIndent();
    }

    this->indent(); this->stream << "<typeid>: " << className << std::endl;
    this->indent(); this->stream << "pos: " << node.getStartPos() << std::endl;
    this->indent(); this->stream << "size: " << node.getSize() << std::endl;
    this->indent(); this->stream << "type: " <<
            (!node.isUntyped() ? this->pool.getTypeName(node.getType()) : "") << std::endl;

    this->leaveIndent();
    if(inArray) {
        this->leaveIndent();
    }
}

void NodeDumper::writeName(const char *fieldName) {
    this->indent(); this->stream << fieldName << ": ";
}

void NodeDumper::operator()(const RootNode &rootNode) {
    this->dump(rootNode);
}

void NodeDumper::dump(std::ostream &out, TypePool &pool, const RootNode &rootNode) {
    NodeDumper writer(out, pool);
    writer(rootNode);
}

} // namespace ast
} // namespace ydsh<commit_msg>fix some notation of node printing<commit_after>/*
 * Copyright (C) 2015-2016 Nagisa Sekiguchi
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <iostream>

#include "node_dumper.h"
#include "node.h"

namespace ydsh {
namespace ast {

void NodeDumper::dump(const char *fieldName, const char *value) {
    std::string str(value);
    this->dump(fieldName, str);
}

void NodeDumper::dump(const char *fieldName, const std::string &value) {
    this->writeName(fieldName);

    this->stream << '"';
    for(char ch : value) {
        bool escape = true;
        switch(ch) {
        case '\t':
            ch = 't';
            break;
        case '\r':
            ch = 'r';
            break;
        case '\n':
            ch = 'n';
            break;
        case '"':
            ch = '"';
            break;
        case '\\':
            ch = '\\';
            break;
        default:
            escape = false;
            break;
        }
        if(escape) {
            this->stream << '\\';
        }
        this->stream << ch;
    }
    this->stream << '"' << std::endl;
}

void NodeDumper::dump(const char *fieldName, const std::vector<Node *> &nodes) {
    this->writeName(fieldName);
    this->stream << std::endl;

    this->enterIndent();
    for(Node *node : nodes) {
        this->indent();
        this->stream << "- ";
        this->dumpNodeHeader(*node, true);
        this->enterIndent();
        node->dump(*this);
        this->leaveIndent();
    }
    this->leaveIndent();
}

void NodeDumper::dump(const char *fieldName, const std::list<Node *> &nodes) {
    this->writeName(fieldName);
    this->stream << std::endl;

    this->enterIndent();
    for(Node *node : nodes) {
        this->indent();
        this->stream << "- ";
        this->dumpNodeHeader(*node, true);
        this->enterIndent();
        node->dump(*this);
        this->leaveIndent();
    }
    this->leaveIndent();
}

void NodeDumper::dump(const char *fieldName, const Node &node) {
    // write field name
    this->writeName(fieldName);

    // write node body
    this->stream << std::endl;
    this->enterIndent();
    this->dump(node);
    this->leaveIndent();
}

void NodeDumper::dump(const char *fieldName, const DSType &type) {
    this->writeName(fieldName);
    this->stream << this->pool.getTypeName(type) << std::endl;
}

void NodeDumper::dumpNull(const char *fieldName) {
    this->writeName(fieldName);
    this->stream << std::endl;
}

void NodeDumper::dump(const Node &node) {
    this->indent();
    this->dumpNodeHeader(node);
    node.dump(*this);
}

void NodeDumper::enterIndent() {
    this->indentLevel++;
}

void NodeDumper::leaveIndent() {
    this->indentLevel--;
}

void NodeDumper::indent() {
    for(unsigned int i = 0; i < this->indentLevel; i++) {
        this->stream << "  ";
    }
}

void NodeDumper::dumpNodeHeader(const Node &node, bool inArray) {
    std::string className = misc::Demangle()(typeid(node));

    this->stream << "__Node: " << std::endl;
    this->enterIndent();
    if(inArray) {
        this->enterIndent();
    }

    this->indent(); this->stream << "__typeid: " << className << std::endl;
    this->indent(); this->stream << "pos: " << node.getStartPos() << std::endl;
    this->indent(); this->stream << "size: " << node.getSize() << std::endl;
    this->indent(); this->stream << "type: " <<
            (!node.isUntyped() ? this->pool.getTypeName(node.getType()) : "") << std::endl;

    this->leaveIndent();
    if(inArray) {
        this->leaveIndent();
    }
}

void NodeDumper::writeName(const char *fieldName) {
    this->indent(); this->stream << fieldName << ": ";
}

void NodeDumper::operator()(const RootNode &rootNode) {
    this->dump(rootNode);
}

void NodeDumper::dump(std::ostream &out, TypePool &pool, const RootNode &rootNode) {
    NodeDumper writer(out, pool);
    writer(rootNode);
}

} // namespace ast
} // namespace ydsh<|endoftext|>


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

#include "CounterImp.h"

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

namespace {

struct AdditiveGlyph
{
    int weight;
    char16_t* glyph;
};

// 1 4999
AdditiveGlyph upperRoman[] =
{
    1000, u"M",
    900, u"CM",
    500, u"D",
    400, u"CD",
    100, u"C",
    90, u"XC",
    50, u"L",
    40, u"XL",
    10, u"X",
    9, u"IX",
    5, u"V",
    4, u"IV",
    1, u"I",
    0, 0
};

// 1 4999
AdditiveGlyph lowerRoman[] =
{
    1000, u"m",
    900, u"cm",
    500, u"d",
    400, u"cd",
    100, u"c",
    90, u"xc",
    50, u"l",
    40, u"xl",
    10, u"x",
    9, u"ix",
    5, u"v",
    4, u"iv",
    1, u"i",
    0, 0
};

std::u16string convertToRoman(int n, AdditiveGlyph* glyphList)
{
    if (n < 0 || 5000 <= n)
        return toString(n);
    std::u16string value;
    for (AdditiveGlyph* i = glyphList; i->glyph; ++i) {
        int t = n / i->weight;
        if (0 < t) {
            n -= t * i->weight;
            while (0 < t--)
                value += i->glyph;
        }
    }
    return value;
}

std::u16string emit(int i, unsigned type)
{
    std::u16string value;
    switch (type) {
    case CSSListStyleTypeValueImp::None:
        break;
    case CSSListStyleTypeValueImp::Disc:
        value = u"\u2022";    // •
        break;
    case CSSListStyleTypeValueImp::Circle:
        value = u"\u25E6";    // ◦
        break;
    case CSSListStyleTypeValueImp::Square:
        // Use u25A0 instead of u25FE for the IPA font for now
        value = u"\u25A0";    // ◾ "\u25FE"
        break;
    case CSSListStyleTypeValueImp::Decimal:
        value = toString(i);
        break;
    case CSSListStyleTypeValueImp::DecimalLeadingZero:
        value = toString(i < 0 ? -i : i);
        if (-9 <= i && i <= 9)
            value = u"0" + value;
        if (i < 0)
            value = u"-" + value;
        break;
    case CSSListStyleTypeValueImp::LowerAlpha:
    case CSSListStyleTypeValueImp::LowerLatin:
        value = std::u16string(1, u'a' + static_cast<unsigned>(i) % 26 - 1);
        break;
    case CSSListStyleTypeValueImp::UpperAlpha:
    case CSSListStyleTypeValueImp::UpperLatin:
        value = std::u16string(1, u'A' + static_cast<unsigned>(i) % 26 - 1);
        break;
    case CSSListStyleTypeValueImp::LowerGreek:
        // This style is only defined because CSS2.1 has it.
        // It doesn't appear to actually be used in Greek texts.
        value = std::u16string(1, u"αβγδεζηθικλμνξοπρστυφχψω"[static_cast<unsigned>(i - 1) % 24]);
        break;
    case CSSListStyleTypeValueImp::LowerRoman:
        value = convertToRoman(i, lowerRoman);
        break;
    case CSSListStyleTypeValueImp::UpperRoman:
        value = convertToRoman(i, upperRoman);
        break;
    case CSSListStyleTypeValueImp::Armenian:
    case CSSListStyleTypeValueImp::Georgian:
    default:
        value = toString(i);
        break;
    }
    return value;
}

}

void CounterImp::nest(int number)
{
    counters.push_back(number);
}

void CounterImp::reset(int number)
{
    if (counters.empty())
        nest(number);
    else
        counters.back() = number;
}

void CounterImp::increment(int number)
{
    assert(!counters.empty());
    counters.back() += number;
}

bool CounterImp::restore()
{
    counters.pop_back();
    return counters.empty();
}

std::u16string CounterImp::eval(unsigned type, CSSAutoNumberingValueImp::CounterContext* context)
{
    this->separator = u"";
    this->listStyle.setValue(type);
    if (counters.empty()) {
        nest(0);
        context->addCounter(this);
    }
    return emit(counters.back(), type);
}

std::u16string CounterImp::eval(const std::u16string& separator, unsigned type, CSSAutoNumberingValueImp::CounterContext* context)
{
    this->separator = separator;
    this->listStyle.setValue(type);
    if (counters.empty()) {
        nest(0);
        context->addCounter(this);
    }
    std::u16string value;
    for (auto i = counters.begin(); i != counters.end(); ++i) {
        if (i != counters.begin())
            value += separator;
        value += emit(*i, type);
    }
    return value;
}

std::u16string CounterImp::getIdentifier()
{
    return identifier;
}

std::u16string CounterImp::getListStyle()
{
    return listStyle.getCssText();
}

std::u16string CounterImp::getSeparator()
{
    return separator;
}

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

#include "CounterImp.h"

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

namespace {

struct AdditiveGlyph
{
    int weight;
    char16_t* glyph;
};

// 1 4999
AdditiveGlyph upperRoman[] =
{
    1000, u"M",
    900, u"CM",
    500, u"D",
    400, u"CD",
    100, u"C",
    90, u"XC",
    50, u"L",
    40, u"XL",
    10, u"X",
    9, u"IX",
    5, u"V",
    4, u"IV",
    1, u"I",
    0, 0
};

// 1 4999
AdditiveGlyph lowerRoman[] =
{
    1000, u"m",
    900, u"cm",
    500, u"d",
    400, u"cd",
    100, u"c",
    90, u"xc",
    50, u"l",
    40, u"xl",
    10, u"x",
    9, u"ix",
    5, u"v",
    4, u"iv",
    1, u"i",
    0, 0
};

std::u16string convertToRoman(int n, AdditiveGlyph* glyphList)
{
    if (n < 0 || 5000 <= n)
        return toString(n);
    std::u16string value;
    for (AdditiveGlyph* i = glyphList; i->glyph; ++i) {
        int t = n / i->weight;
        if (0 < t) {
            n -= t * i->weight;
            while (0 < t--)
                value += i->glyph;
        }
    }
    return value;
}

std::u16string emit(int i, unsigned type)
{
    std::u16string value;
    switch (type) {
    case CSSListStyleTypeValueImp::None:
        break;
    case CSSListStyleTypeValueImp::Disc:
        value = u"\u2022";    // •
        break;
    case CSSListStyleTypeValueImp::Circle:
        value = u"\u25E6";    // ◦
        break;
    case CSSListStyleTypeValueImp::Square:
        // Use u25A0 instead of u25FE for the IPA font for now
        value = u"\u25A0";    // ◾ "\u25FE"
        break;
    case CSSListStyleTypeValueImp::Decimal:
        value = toString(i);
        break;
    case CSSListStyleTypeValueImp::DecimalLeadingZero:
        value = toString(i < 0 ? -i : i);
        if (-9 <= i && i <= 9)
            value = u"0" + value;
        if (i < 0)
            value = u"-" + value;
        break;
    case CSSListStyleTypeValueImp::LowerAlpha:
    case CSSListStyleTypeValueImp::LowerLatin:
        value = std::u16string(1, u'a' + static_cast<unsigned>(i) % 26 - 1);
        break;
    case CSSListStyleTypeValueImp::UpperAlpha:
    case CSSListStyleTypeValueImp::UpperLatin:
        value = std::u16string(1, u'A' + static_cast<unsigned>(i) % 26 - 1);
        break;
    case CSSListStyleTypeValueImp::LowerGreek:
        // This style is only defined because CSS2.1 has it.
        // It doesn't appear to actually be used in Greek texts.
        value = std::u16string(1, u"αβγδεζηθικλμνξοπρστυφχψω"[static_cast<unsigned>(i - 1) % 24]);
        break;
    case CSSListStyleTypeValueImp::LowerRoman:
        value = convertToRoman(i, lowerRoman);
        break;
    case CSSListStyleTypeValueImp::UpperRoman:
        value = convertToRoman(i, upperRoman);
        break;
    case CSSListStyleTypeValueImp::Armenian:
    case CSSListStyleTypeValueImp::Georgian:
    default:
        value = toString(i);
        break;
    }
    return value;
}

}

void CounterImp::nest(int number)
{
    counters.push_back(number);
}

void CounterImp::reset(int number)
{
    if (counters.empty())
        nest(number);
    else
        counters.back() = number;
}

void CounterImp::increment(int number)
{
    if (counters.empty())
        nest(0);
    counters.back() += number;
}

bool CounterImp::restore()
{
    counters.pop_back();
    return counters.empty();
}

std::u16string CounterImp::eval(unsigned type, CSSAutoNumberingValueImp::CounterContext* context)
{
    this->separator = u"";
    this->listStyle.setValue(type);
    if (counters.empty()) {
        nest(0);
        context->addCounter(this);
    }
    return emit(counters.back(), type);
}

std::u16string CounterImp::eval(const std::u16string& separator, unsigned type, CSSAutoNumberingValueImp::CounterContext* context)
{
    this->separator = separator;
    this->listStyle.setValue(type);
    if (counters.empty()) {
        nest(0);
        context->addCounter(this);
    }
    std::u16string value;
    for (auto i = counters.begin(); i != counters.end(); ++i) {
        if (i != counters.begin())
            value += separator;
        value += emit(*i, type);
    }
    return value;
}

std::u16string CounterImp::getIdentifier()
{
    return identifier;
}

std::u16string CounterImp::getListStyle()
{
    return listStyle.getCssText();
}

std::u16string CounterImp::getSeparator()
{
    return separator;
}

}
}
}
}
<|endoftext|>


<commit_before>// ------------------------------------------------------------------------
// eca-curses.cpp: Curses implementation of the console user interface.
// Copyright (C) 1999-2002 Kai Vehmanen (kai.vehmanen@wakkanet.fi)
//
// 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
// ------------------------------------------------------------------------

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <map>
#include <string>

#if defined ECA_USE_NCURSES || defined ECA_USE_TERMCAP

#ifdef ECA_HAVE_NCURSES_CURSES_H
#include <ncurses/curses.h>
#include <ncurses/term.h>
#else
#include <curses.h>
#include <term.h>
#endif

#define READLINE_LIBRARY
#include <readline.h>
#include <history.h>

#include <eca-iamode-parser.h>
#include <eca-version.h>
#include <kvu_utils.h> /* kvu_string_search_and_replace() */

#include "eca-curses.h"

#if RL_READLINE_VERSION >= 0x0402
static char** ecasound_completion (const char *text, int start, int end);
static char* ecasound_command_generator (const char* text, int state);
#else
static char** ecasound_completion (char *text, int start, int end);
static char* ecasound_command_generator (char* text, int state);
#endif

using namespace std;

ECA_CURSES::ECA_CURSES(void)
{
  init_readline_support();
}

ECA_CURSES::~ECA_CURSES(void)
{
}

void ECA_CURSES::print(const std::string& msg)
{
  cout << msg << endl;
}

void ECA_CURSES::print_banner(void)
{
  cout << "****************************************************************************\n";
  cout << "*";
  setupterm((char *)0, 1, (int *)0);
  putp(tigetstr("bold"));
  cout << "               ecasound v"
       << ecasound_library_version
       << " (C) 1997-2002 Kai Vehmanen                 ";
  putp(tigetstr("sgr0"));
  cout << "\n";
  cout << "****************************************************************************\n";
}

void ECA_CURSES::read_command(const string& prompt)
{
  last_cmdchar_repp = readline(const_cast<char*>(prompt.c_str()));
  if (last_cmdchar_repp != 0) {
    add_history(last_cmdchar_repp);
    last_cmd_rep = last_cmdchar_repp;
    free(last_cmdchar_repp);
  }
}

const string& ECA_CURSES::last_command(void) const
{
  return(last_cmd_rep);
}

void ECA_CURSES::init_readline_support(void)
{
  /* for conditional parsing of ~/.inputrc file. */
  rl_readline_name = "ecasound";

  /* we want to attempt completion first */
#if RL_READLINE_VERSION >= 0x0402
  rl_attempted_completion_function = (rl_completion_func_t*)ecasound_completion;
#else
  rl_attempted_completion_function = (CPPFunction *)ecasound_completion;
#endif
}

/* **************************************************************** */
/*                                                                  */
/*                  Interface to Readline Completion                */
/*                                                                  */
/* **************************************************************** */

char *command_generator ();
char **fileman_completion ();

/**
 * Attempt to complete on the contents of TEXT.  START and END bound the
 * region of rl_line_buffer that contains the word to complete.  TEXT is
 * the word to complete.  We can use the entire contents of rl_line_buffer
 * in case we want to do some simple parsing.  Return the array of matches,
 * or NULL if there aren't any.
 */
#if RL_READLINE_VERSION >= 0x0402
char** ecasound_completion (const char *text, int start, int end)
#else
char** ecasound_completion (char *text, int start, int end)
#endif
{
  char **matches;
  matches = (char **)NULL;

  /* complete only the first command, otherwise complete files in
   * the current directory */
  if (start == 0) {
#if RL_READLINE_VERSION >= 0x0402
    matches = rl_completion_matches (text, (rl_compentry_func_t *)ecasound_command_generator);
#else
    matches = completion_matches (text, (CPFunction *)ecasound_command_generator);
#endif
  }
  return (matches);
}

/**
 * Generator function for command completion.  STATE lets us know whether
 * to start from scratch; without any state (i.e. STATE == 0), then we
 * start at the top of the list.
 */
#if RL_READLINE_VERSION >= 0x0402
char* ecasound_command_generator (const char* text, int state)
#else
char* ecasound_command_generator (char* text, int state)
#endif
{
  static int list_index, len;
  static const map<string,int>& map_ref = ECA_IAMODE_PARSER::registered_commands();
  static map<string,int>::const_iterator p;
  static string cmd;

  /* If this is a new word to complete, initialize now.  This includes
   * saving the length of TEXT for efficiency, and initializing the index
   * variable to 0
   */
  if (!state) {
      list_index = 0;
      p = map_ref.begin();
      len = strlen (text);
  }

  /* Return the next name which partially matches from the command list */
  while (p != map_ref.end()) {
      cmd = p->first;
      list_index++;
      ++p;
      if (p != map_ref.end()) {
	string hyphenstr = kvu_string_search_and_replace(text, '_', '-');
	if (strncmp(hyphenstr.c_str(), cmd.c_str(), len) == 0) {
	  return(strdup(cmd.c_str()));
	}
      }
  }
  return ((char *)0);
}

#else

#include "eca-curses.h"

ECA_CURSES::ECA_CURSES(void) {}
ECA_CURSES::~ECA_CURSES(void) {}
void ECA_CURSES::print(const std::string& msg) {}
void ECA_CURSES::print_banner(void) {}
void ECA_CURSES::read_command(const std::string& prompt) {}
const std::string& ECA_CURSES::last_command(void) const { static std::string empty; return(empty); }
void ECA_CURSES::init_readline_support(void) {}

#endif /* defined ECA_USE_NCURSES || defined ECA_USE_TERMCAP */
<commit_msg>Bugfix to handle ctrl-d properly.<commit_after>// ------------------------------------------------------------------------
// eca-curses.cpp: Curses implementation of the console user interface.
// Copyright (C) 1999-2002 Kai Vehmanen (kai.vehmanen@wakkanet.fi)
//
// 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
// ------------------------------------------------------------------------

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#include <iostream>
#include <map>
#include <string>

#if defined ECA_USE_NCURSES || defined ECA_USE_TERMCAP

#ifdef ECA_HAVE_NCURSES_CURSES_H
#include <ncurses/curses.h>
#include <ncurses/term.h>
#else
#include <curses.h>
#include <term.h>
#endif

#define READLINE_LIBRARY
#include <readline.h>
#include <history.h>

#include <eca-iamode-parser.h>
#include <eca-version.h>
#include <kvu_utils.h> /* kvu_string_search_and_replace() */

#include "eca-curses.h"

#if RL_READLINE_VERSION >= 0x0402
static char** ecasound_completion (const char *text, int start, int end);
static char* ecasound_command_generator (const char* text, int state);
#else
static char** ecasound_completion (char *text, int start, int end);
static char* ecasound_command_generator (char* text, int state);
#endif

using namespace std;

ECA_CURSES::ECA_CURSES(void)
{
  init_readline_support();
}

ECA_CURSES::~ECA_CURSES(void)
{
}

void ECA_CURSES::print(const std::string& msg)
{
  cout << msg << endl;
}

void ECA_CURSES::print_banner(void)
{
  cout << "****************************************************************************\n";
  cout << "*";
  setupterm((char *)0, 1, (int *)0);
  putp(tigetstr("bold"));
  cout << "               ecasound v"
       << ecasound_library_version
       << " (C) 1997-2002 Kai Vehmanen                 ";
  putp(tigetstr("sgr0"));
  cout << "\n";
  cout << "****************************************************************************\n";
}

void ECA_CURSES::read_command(const string& prompt)
{
  last_cmdchar_repp = readline(const_cast<char*>(prompt.c_str()));
  if (last_cmdchar_repp != 0) {
    add_history(last_cmdchar_repp);
    last_cmd_rep = last_cmdchar_repp;
    free(last_cmdchar_repp);
  }
  else {
    /* handle EOF */
    last_cmd_rep = "q";
  }
}

const string& ECA_CURSES::last_command(void) const
{
  return(last_cmd_rep);
}

void ECA_CURSES::init_readline_support(void)
{
  /* for conditional parsing of ~/.inputrc file. */
  rl_readline_name = "ecasound";

  /* we want to attempt completion first */
#if RL_READLINE_VERSION >= 0x0402
  rl_attempted_completion_function = (rl_completion_func_t*)ecasound_completion;
#else
  rl_attempted_completion_function = (CPPFunction *)ecasound_completion;
#endif
}

/* **************************************************************** */
/*                                                                  */
/*                  Interface to Readline Completion                */
/*                                                                  */
/* **************************************************************** */

char *command_generator ();
char **fileman_completion ();

/**
 * Attempt to complete on the contents of TEXT.  START and END bound the
 * region of rl_line_buffer that contains the word to complete.  TEXT is
 * the word to complete.  We can use the entire contents of rl_line_buffer
 * in case we want to do some simple parsing.  Return the array of matches,
 * or NULL if there aren't any.
 */
#if RL_READLINE_VERSION >= 0x0402
char** ecasound_completion (const char *text, int start, int end)
#else
char** ecasound_completion (char *text, int start, int end)
#endif
{
  char **matches;
  matches = (char **)NULL;

  /* complete only the first command, otherwise complete files in
   * the current directory */
  if (start == 0) {
#if RL_READLINE_VERSION >= 0x0402
    matches = rl_completion_matches (text, (rl_compentry_func_t *)ecasound_command_generator);
#else
    matches = completion_matches (text, (CPFunction *)ecasound_command_generator);
#endif
  }
  return (matches);
}

/**
 * Generator function for command completion.  STATE lets us know whether
 * to start from scratch; without any state (i.e. STATE == 0), then we
 * start at the top of the list.
 */
#if RL_READLINE_VERSION >= 0x0402
char* ecasound_command_generator (const char* text, int state)
#else
char* ecasound_command_generator (char* text, int state)
#endif
{
  static int list_index, len;
  static const map<string,int>& map_ref = ECA_IAMODE_PARSER::registered_commands();
  static map<string,int>::const_iterator p;
  static string cmd;

  /* If this is a new word to complete, initialize now.  This includes
   * saving the length of TEXT for efficiency, and initializing the index
   * variable to 0
   */
  if (!state) {
      list_index = 0;
      p = map_ref.begin();
      len = strlen (text);
  }

  /* Return the next name which partially matches from the command list */
  while (p != map_ref.end()) {
      cmd = p->first;
      list_index++;
      ++p;
      if (p != map_ref.end()) {
	string hyphenstr = kvu_string_search_and_replace(text, '_', '-');
	if (strncmp(hyphenstr.c_str(), cmd.c_str(), len) == 0) {
	  return(strdup(cmd.c_str()));
	}
      }
  }
  return ((char *)0);
}

#else

#include "eca-curses.h"

ECA_CURSES::ECA_CURSES(void) {}
ECA_CURSES::~ECA_CURSES(void) {}
void ECA_CURSES::print(const std::string& msg) {}
void ECA_CURSES::print_banner(void) {}
void ECA_CURSES::read_command(const std::string& prompt) {}
const std::string& ECA_CURSES::last_command(void) const { static std::string empty; return(empty); }
void ECA_CURSES::init_readline_support(void) {}

#endif /* defined ECA_USE_NCURSES || defined ECA_USE_TERMCAP */
<|endoftext|>


<commit_before>#include "../TCPServer.hpp"
#include "../IOUtils.hpp"
#include "../SysUtils.hpp"

#include <cstdlib>
#include <memory>
#include <iostream>
#include <unistd.h>

void handleClient(std::shared_ptr<TCPConnection> conn)
{
    static constexpr int MAXLINE = 8192;

    int sockfd = conn->sockfd();
    char buf[MAXLINE];

    ssize_t n;

    while (true) {
        n = read(sockfd, buf, MAXLINE - 1);
        if (n == 0) {
            std::cerr << "connection close by client[" << conn->address() << "]" << std::endl;
            return;
        }
        if (n > 0) {
            buf[n] = '\0';
            std::cout << "read from client[" << conn->address() << "]: " << buf << std::endl;
            if (writen(sockfd, buf, n) == -1) {
                std::cerr << "handleClient(): write error - " << strerror(errno) << std::endl;
                exit(EXIT_FAILURE);
            } else {
                std::cout << "write to client[" << conn->address() << "]: " << buf << std::endl;
            }
        } else if (n == -1 && errno != EINTR){
            std::cerr << "handleClient(): read error - " << strerror(errno) << std::endl;
            exit(EXIT_FAILURE);
        }
    }
}

int main(int argc, char *argv[])
{
    Signal(SIGCHLD, sigchld_handler);
    Signal(SIGPIPE, SIG_IGN);

    std::unique_ptr<TCPServer> server = nullptr;
    try {
        server.reset(new TCPServer("0.0.0.0", 9388));
    } catch (TCPServerError &e) {
        std::cerr << e.what() << std::endl;
        exit(EXIT_FAILURE);
    }

    while (true)
    {
        std::shared_ptr<TCPConnection> conn;
        try {
            conn = server->accept();
            std::cout << "accept new connection[" << conn->address() << "]" << std::endl;
        } catch (const TCPServerError &e) {
            std::cerr << e.what() << std::endl;
            continue;
        }

        auto n = fork();
        if (n == -1) {
            std::cerr << "fork error: %s" << strerror(errno) << std::endl;
            exit(EXIT_FAILURE);
        }
        if (n == 0) {
            handleClient(conn);
            exit(EXIT_SUCCESS);
        }
    }

    return 0;
}
<commit_msg>fix buffer length<commit_after>#include "../TCPServer.hpp"
#include "../IOUtils.hpp"
#include "../SysUtils.hpp"

#include <cstdlib>
#include <memory>
#include <iostream>
#include <unistd.h>

void handleClient(std::shared_ptr<TCPConnection> conn)
{
    static constexpr int MAXLINE = 8192;

    int sockfd = conn->sockfd();
    char buf[MAXLINE + 1];

    ssize_t n;

    while (true) {
        n = read(sockfd, buf, MAXLINE);
        if (n == 0) {
            std::cerr << "connection close by client[" << conn->address() << "]" << std::endl;
            return;
        }
        if (n > 0) {
            buf[n] = '\0';
            std::cout << "read from client[" << conn->address() << "]: " << buf << std::endl;
            if (writen(sockfd, buf, n) == -1) {
                std::cerr << "handleClient(): write error - " << strerror(errno) << std::endl;
                exit(EXIT_FAILURE);
            } else {
                std::cout << "write to client[" << conn->address() << "]: " << buf << std::endl;
            }
        } else if (n == -1 && errno != EINTR){
            std::cerr << "handleClient(): read error - " << strerror(errno) << std::endl;
            exit(EXIT_FAILURE);
        }
    }
}

int main(int argc, char *argv[])
{
    Signal(SIGCHLD, sigchld_handler);
    Signal(SIGPIPE, SIG_IGN);

    std::unique_ptr<TCPServer> server = nullptr;
    try {
        server.reset(new TCPServer("0.0.0.0", 9388));
    } catch (TCPServerError &e) {
        std::cerr << e.what() << std::endl;
        exit(EXIT_FAILURE);
    }

    while (true)
    {
        std::shared_ptr<TCPConnection> conn;
        try {
            conn = server->accept();
            std::cout << "accept new connection[" << conn->address() << "]" << std::endl;
        } catch (const TCPServerError &e) {
            std::cerr << e.what() << std::endl;
            continue;
        }

        auto n = fork();
        if (n == -1) {
            std::cerr << "fork error: %s" << strerror(errno) << std::endl;
            exit(EXIT_FAILURE);
        }
        if (n == 0) {
            handleClient(conn);
            exit(EXIT_SUCCESS);
        }
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
Copyright (C) 2001-present by Serge Lamikhov-Center

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.
*/

#ifndef ELFIO_STRINGS_HPP
#define ELFIO_STRINGS_HPP

#include <cstdlib>
#include <cstring>
#include <string>

namespace ELFIO {

//------------------------------------------------------------------------------
template <class S> class string_section_accessor_template
{
  public:
    //------------------------------------------------------------------------------
    explicit string_section_accessor_template( S* section )
        : string_section( section )
    {
    }

    //------------------------------------------------------------------------------
    const char* get_string( Elf_Word index ) const
    {
        if ( string_section ) {
            if ( index < string_section->get_size() ) {
                const char* data = string_section->get_data();
                if ( nullptr != data ) {
                    return data + index;
                }
            }
        }

        return nullptr;
    }

    //------------------------------------------------------------------------------
    Elf_Word add_string( const char* str )
    {
        Elf_Word current_position = 0;

        if ( string_section ) {
            // Strings are addeded to the end of the current section data
            current_position =
                static_cast<Elf_Word>( string_section->get_size() );

            if ( current_position == 0 ) {
                char empty_string = '\0';
                string_section->append_data( &empty_string, 1 );
                current_position++;
            }
            string_section->append_data(
                str, static_cast<Elf_Word>( std::strlen( str ) + 1 ) );
        }

        return current_position;
    }

    //------------------------------------------------------------------------------
    Elf_Word add_string( const std::string& str )
    {
        return add_string( str.c_str() );
    }

    //------------------------------------------------------------------------------
  private:
    S* string_section;
};

using string_section_accessor = string_section_accessor_template<section>;
using const_string_section_accessor =
    string_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_STRINGS_HPP
<commit_msg>Validate that strings in table are null terminated<commit_after>/*
Copyright (C) 2001-present by Serge Lamikhov-Center

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.
*/

#ifndef ELFIO_STRINGS_HPP
#define ELFIO_STRINGS_HPP

#include <cstdlib>
#include <cstring>
#include <string>

namespace ELFIO {

//------------------------------------------------------------------------------
template <class S> class string_section_accessor_template
{
  public:
    //------------------------------------------------------------------------------
    explicit string_section_accessor_template( S* section )
        : string_section( section )
    {
    }

    //------------------------------------------------------------------------------
    const char* get_string( Elf_Word index ) const
    {
        if ( string_section ) {
            if ( index < string_section->get_size() ) {
                const char* data = string_section->get_data();
                if ( nullptr != data ) {
                    size_t string_length = strnlen(
                        data + index, string_section->get_size() - index );
                    if ( string_length <
                         ( string_section->get_size() - index ) )
                        return data + index;
                }
            }
        }

        return nullptr;
    }

    //------------------------------------------------------------------------------
    Elf_Word add_string( const char* str )
    {
        Elf_Word current_position = 0;

        if ( string_section ) {
            // Strings are addeded to the end of the current section data
            current_position =
                static_cast<Elf_Word>( string_section->get_size() );

            if ( current_position == 0 ) {
                char empty_string = '\0';
                string_section->append_data( &empty_string, 1 );
                current_position++;
            }
            string_section->append_data(
                str, static_cast<Elf_Word>( std::strlen( str ) + 1 ) );
        }

        return current_position;
    }

    //------------------------------------------------------------------------------
    Elf_Word add_string( const std::string& str )
    {
        return add_string( str.c_str() );
    }

    //------------------------------------------------------------------------------
  private:
    S* string_section;
};

using string_section_accessor = string_section_accessor_template<section>;
using const_string_section_accessor =
    string_section_accessor_template<const section>;

} // namespace ELFIO

#endif // ELFIO_STRINGS_HPP
<|endoftext|>


<commit_before>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2014, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "MainUI.h"
#include "ui_MainUI.h"

#include "ConfigUI.h"

MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){
  ui->setupUi(this); //load the designer file
  //setupIcons();
  ui->radio_apps->setChecked(true); //always default to starting here
  ui->tool_stop->setVisible(false); //no search running initially
  ui->tool_configure->setVisible(false); //app search initially set

  livetime = new QTimer(this);
    livetime->setInterval(500); //1/2 second for live searches
    livetime->setSingleShot(true);

  workthread = new QThread(this);
	workthread->setObjectName("Lumina Search Process");

  searcher = new Worker();
    searcher->moveToThread(workthread);

  closeShort = new QShortcut(QKeySequence(tr("Esc")), this);

  //Setup the connections
  connect(livetime, SIGNAL(timeout()), this, SLOT(startSearch()) );
  connect(this, SIGNAL(SearchTerm(QString, bool)), searcher, SLOT(StartSearch(QString, bool)) );
  connect(searcher, SIGNAL(FoundItem(QString)), this, SLOT(foundSearchItem(QString)) );
  connect(searcher, SIGNAL(SearchUpdate(QString)), this, SLOT(searchMessage(QString)) );
  connect(searcher, SIGNAL(SearchDone()), this, SLOT(searchFinished()) );
  connect(ui->tool_stop, SIGNAL(clicked()), this, SLOT(stopSearch()) );
  connect(ui->push_done, SIGNAL(clicked()), this, SLOT(closeApplication()) );
  connect(ui->push_launch, SIGNAL(clicked()), this, SLOT(LaunchItem()) );
  connect(ui->line_search, SIGNAL(textEdited(QString)), this, SLOT(searchChanged()) );
  connect(ui->line_search, SIGNAL(returnPressed()), this, SLOT(LaunchItem()) );
  connect(ui->radio_apps, SIGNAL(toggled(bool)), this, SLOT(searchTypeChanged()) );
  connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(LaunchItem(QListWidgetItem*)) );
  connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(LaunchItem(QListWidgetItem*)) );
  connect(ui->tool_configure, SIGNAL(clicked()), this, SLOT(configureSearch()) );
  connect(closeShort, SIGNAL(activated()), this, SLOT( close() ) );

  //Setup the settings file
  settings = LUtils::openSettings("lumina-desktop", "lumina-search",this);
  searcher->startDir = settings->value("StartSearchDir", QDir::homePath()).toString();
  searcher->skipDirs = settings->value("SkipSearchDirs", QStringList()).toStringList();
  updateDefaultStatusTip();
  this->show();
  workthread->start();
  QTimer::singleShot(0,this, SLOT(setupIcons()) );
}

MainUI::~MainUI(){
  searcher->StopSearch();
  workthread->quit();
  workthread->wait();
}

void MainUI::setupIcons(){
  //Setup the icons
  this->setWindowIcon( LXDG::findIcon("edit-find","") );
  ui->push_launch->setIcon( LXDG::findIcon("quickopen","") );
  ui->push_done->setIcon( LXDG::findIcon("window-close","") );
  ui->tool_stop->setIcon( LXDG::findIcon("dialog-cancel","") );
  ui->tool_configure->setIcon( LXDG::findIcon("configure","") );
}

// ===============
//    PUBLIC FUNCTIONS (for input handling primarily)
// ===============
void MainUI::disableExcludes(){
  searcher->skipDirs.clear();
  updateDefaultStatusTip();
}

void MainUI::setSearchDirectory(QString path){
  ui->radio_files->setChecked(true);
  searcher->startDir = path;
  updateDefaultStatusTip();
}

void MainUI::setSearchTerm(QString text){
  ui->line_search->setText(text);
}

//==============
//  PRIVATE
//==============
void MainUI::updateDefaultStatusTip(){
  if(ui->radio_files->isChecked()){
    QString txt = tr("Search: %1 -- Smart: %2");
    QString dir = searcher->startDir;
      dir.replace(QDir::homePath(), "~");
    QString smart = searcher->skipDirs.isEmpty() ? tr("Off"): tr("On");
    txt = txt.arg(dir,smart);
    ui->statusbar->showMessage(txt);
  }
}

//==============
//  PRIVATE SLOTS
//==============
void MainUI::LaunchItem(){
int index = ui->listWidget->currentRow();
if(index<0 && ui->listWidget->count()>0){ index = 0; } //grab the first item instead
else if(index<0){ return; } //no items available/selected
QString item = ui->listWidget->item(index)->whatsThis();
QProcess::startDetached("lumina-open \""+item+"\"");
//Close the search utility if an application was launched (quick launch functionality)
if(ui->radio_apps->isChecked()){ this->close(); }
}

void MainUI::LaunchItem(QListWidgetItem *item){
    QProcess::startDetached("lumina-open \""+item->whatsThis()+"\"");
}

void MainUI::searchTypeChanged(){
  startSearch();
}

void MainUI::configureSearch(){
  ConfigUI dlg(this);
    dlg.loadInitialValues( settings->value("StartSearchDir",QDir::homePath()).toString(), settings->value("SkipSearchDirs",QStringList()).toStringList());
    dlg.exec();
  if(dlg.newStartDir.isEmpty()){ return; }//cancelled
  QString startdir = dlg.newStartDir;
  QStringList skipdirs = dlg.newSkipDirs;

  //Save these values for later (if selected)
  if(dlg.newDefaults){
    //save these values as the new defaults
    settings->setValue("StartSearchDir", startdir);
    settings->setValue("SkipSearchDirs", skipdirs);
  }

  //Set these values in the searcher
  searcher->startDir = startdir;
  searcher->skipDirs = skipdirs;
  updateDefaultStatusTip();
}

void MainUI::searchChanged(){
  if(livetime->isActive()){ livetime->stop(); }
  livetime->start();
}

//Worker Interaction
void MainUI::startSearch(){
  ui->listWidget->clear();
  stopSearch(); //just in case a search is still running
  if(ui->line_search->text().isEmpty()){ updateDefaultStatusTip(); return; } //nothing to search for

  //emit the proper signal for the worker
  if(!workthread->isRunning()){ workthread->start(); } //make sure the thread is running
  emit SearchTerm(ui->line_search->text(), ui->radio_apps->isChecked());
  ui->tool_stop->setVisible(true);
  ui->tool_configure->setVisible(false);
}

void MainUI::foundSearchItem(QString path){
   //To get the worker's results
  QListWidgetItem *it = new QListWidgetItem;
    it->setWhatsThis(path);
    it->setToolTip(path);
  //Now setup the visuals
  if(path.simplified().endsWith(".desktop")){
    bool ok = false;
    XDGDesktop desk(path);
    if( !desk.isValid() ){delete it; return; } //invalid file
    it->setText(desk.name);
    it->setIcon( LXDG::findIcon(desk.icon, "application-x-desktop") );
  }else{
    if(QFileInfo(path).isDir()){
      it->setIcon( LXDG::findIcon("inode-directory","") );
      it->setText( path.replace(QDir::homePath(), "~") );
    }else{
      if(QFileInfo(path).isExecutable()){
	it->setIcon( LXDG::findIcon("application-x-executable","") );
      }else{
        it->setIcon( LXDG::findMimeIcon(path.section("/",-1).section(".",-1)) );
      }
      it->setText( path.section("/",-1) );
    }

  }
  //Now add it to the widget
  ui->listWidget->addItem(it);
  if(ui->listWidget->count()>100){ searcher->StopSearch(); } //just in case
}

void MainUI::stopSearch(){
  searcher->StopSearch();
  ui->tool_stop->setVisible(false);
  ui->tool_configure->setVisible(ui->radio_files->isChecked());
  updateDefaultStatusTip();
}

void MainUI::searchMessage(QString msg){
  ui->statusbar->showMessage(msg,2000);
}

void MainUI::searchFinished(){
  ui->tool_stop->setVisible(false);
  ui->tool_configure->setVisible(ui->radio_files->isChecked());
  updateDefaultStatusTip();
}
<commit_msg>Fix a missing include in lumina-search<commit_after>//===========================================
//  Lumina-DE source code
//  Copyright (c) 2014, Ken Moore
//  Available under the 3-clause BSD license
//  See the LICENSE file for full details
//===========================================
#include "MainUI.h"
#include "ui_MainUI.h"

#include "ConfigUI.h"

#include <LUtils.h>

MainUI::MainUI() : QMainWindow(), ui(new Ui::MainUI){
  ui->setupUi(this); //load the designer file
  //setupIcons();
  ui->radio_apps->setChecked(true); //always default to starting here
  ui->tool_stop->setVisible(false); //no search running initially
  ui->tool_configure->setVisible(false); //app search initially set

  livetime = new QTimer(this);
    livetime->setInterval(500); //1/2 second for live searches
    livetime->setSingleShot(true);

  workthread = new QThread(this);
	workthread->setObjectName("Lumina Search Process");

  searcher = new Worker();
    searcher->moveToThread(workthread);

  closeShort = new QShortcut(QKeySequence(tr("Esc")), this);

  //Setup the connections
  connect(livetime, SIGNAL(timeout()), this, SLOT(startSearch()) );
  connect(this, SIGNAL(SearchTerm(QString, bool)), searcher, SLOT(StartSearch(QString, bool)) );
  connect(searcher, SIGNAL(FoundItem(QString)), this, SLOT(foundSearchItem(QString)) );
  connect(searcher, SIGNAL(SearchUpdate(QString)), this, SLOT(searchMessage(QString)) );
  connect(searcher, SIGNAL(SearchDone()), this, SLOT(searchFinished()) );
  connect(ui->tool_stop, SIGNAL(clicked()), this, SLOT(stopSearch()) );
  connect(ui->push_done, SIGNAL(clicked()), this, SLOT(closeApplication()) );
  connect(ui->push_launch, SIGNAL(clicked()), this, SLOT(LaunchItem()) );
  connect(ui->line_search, SIGNAL(textEdited(QString)), this, SLOT(searchChanged()) );
  connect(ui->line_search, SIGNAL(returnPressed()), this, SLOT(LaunchItem()) );
  connect(ui->radio_apps, SIGNAL(toggled(bool)), this, SLOT(searchTypeChanged()) );
  connect(ui->listWidget, SIGNAL(itemDoubleClicked(QListWidgetItem*)), this, SLOT(LaunchItem(QListWidgetItem*)) );
  connect(ui->listWidget, SIGNAL(itemActivated(QListWidgetItem*)), this, SLOT(LaunchItem(QListWidgetItem*)) );
  connect(ui->tool_configure, SIGNAL(clicked()), this, SLOT(configureSearch()) );
  connect(closeShort, SIGNAL(activated()), this, SLOT( close() ) );

  //Setup the settings file
  settings = LUtils::openSettings("lumina-desktop", "lumina-search",this);
  searcher->startDir = settings->value("StartSearchDir", QDir::homePath()).toString();
  searcher->skipDirs = settings->value("SkipSearchDirs", QStringList()).toStringList();
  updateDefaultStatusTip();
  this->show();
  workthread->start();
  QTimer::singleShot(0,this, SLOT(setupIcons()) );
}

MainUI::~MainUI(){
  searcher->StopSearch();
  workthread->quit();
  workthread->wait();
}

void MainUI::setupIcons(){
  //Setup the icons
  this->setWindowIcon( LXDG::findIcon("edit-find","") );
  ui->push_launch->setIcon( LXDG::findIcon("quickopen","") );
  ui->push_done->setIcon( LXDG::findIcon("window-close","") );
  ui->tool_stop->setIcon( LXDG::findIcon("dialog-cancel","") );
  ui->tool_configure->setIcon( LXDG::findIcon("configure","") );
}

// ===============
//    PUBLIC FUNCTIONS (for input handling primarily)
// ===============
void MainUI::disableExcludes(){
  searcher->skipDirs.clear();
  updateDefaultStatusTip();
}

void MainUI::setSearchDirectory(QString path){
  ui->radio_files->setChecked(true);
  searcher->startDir = path;
  updateDefaultStatusTip();
}

void MainUI::setSearchTerm(QString text){
  ui->line_search->setText(text);
}

//==============
//  PRIVATE
//==============
void MainUI::updateDefaultStatusTip(){
  if(ui->radio_files->isChecked()){
    QString txt = tr("Search: %1 -- Smart: %2");
    QString dir = searcher->startDir;
      dir.replace(QDir::homePath(), "~");
    QString smart = searcher->skipDirs.isEmpty() ? tr("Off"): tr("On");
    txt = txt.arg(dir,smart);
    ui->statusbar->showMessage(txt);
  }
}

//==============
//  PRIVATE SLOTS
//==============
void MainUI::LaunchItem(){
int index = ui->listWidget->currentRow();
if(index<0 && ui->listWidget->count()>0){ index = 0; } //grab the first item instead
else if(index<0){ return; } //no items available/selected
QString item = ui->listWidget->item(index)->whatsThis();
QProcess::startDetached("lumina-open \""+item+"\"");
//Close the search utility if an application was launched (quick launch functionality)
if(ui->radio_apps->isChecked()){ this->close(); }
}

void MainUI::LaunchItem(QListWidgetItem *item){
    QProcess::startDetached("lumina-open \""+item->whatsThis()+"\"");
}

void MainUI::searchTypeChanged(){
  startSearch();
}

void MainUI::configureSearch(){
  ConfigUI dlg(this);
    dlg.loadInitialValues( settings->value("StartSearchDir",QDir::homePath()).toString(), settings->value("SkipSearchDirs",QStringList()).toStringList());
    dlg.exec();
  if(dlg.newStartDir.isEmpty()){ return; }//cancelled
  QString startdir = dlg.newStartDir;
  QStringList skipdirs = dlg.newSkipDirs;

  //Save these values for later (if selected)
  if(dlg.newDefaults){
    //save these values as the new defaults
    settings->setValue("StartSearchDir", startdir);
    settings->setValue("SkipSearchDirs", skipdirs);
  }

  //Set these values in the searcher
  searcher->startDir = startdir;
  searcher->skipDirs = skipdirs;
  updateDefaultStatusTip();
}

void MainUI::searchChanged(){
  if(livetime->isActive()){ livetime->stop(); }
  livetime->start();
}

//Worker Interaction
void MainUI::startSearch(){
  ui->listWidget->clear();
  stopSearch(); //just in case a search is still running
  if(ui->line_search->text().isEmpty()){ updateDefaultStatusTip(); return; } //nothing to search for

  //emit the proper signal for the worker
  if(!workthread->isRunning()){ workthread->start(); } //make sure the thread is running
  emit SearchTerm(ui->line_search->text(), ui->radio_apps->isChecked());
  ui->tool_stop->setVisible(true);
  ui->tool_configure->setVisible(false);
}

void MainUI::foundSearchItem(QString path){
   //To get the worker's results
  QListWidgetItem *it = new QListWidgetItem;
    it->setWhatsThis(path);
    it->setToolTip(path);
  //Now setup the visuals
  if(path.simplified().endsWith(".desktop")){
    bool ok = false;
    XDGDesktop desk(path);
    if( !desk.isValid() ){delete it; return; } //invalid file
    it->setText(desk.name);
    it->setIcon( LXDG::findIcon(desk.icon, "application-x-desktop") );
  }else{
    if(QFileInfo(path).isDir()){
      it->setIcon( LXDG::findIcon("inode-directory","") );
      it->setText( path.replace(QDir::homePath(), "~") );
    }else{
      if(QFileInfo(path).isExecutable()){
	it->setIcon( LXDG::findIcon("application-x-executable","") );
      }else{
        it->setIcon( LXDG::findMimeIcon(path.section("/",-1).section(".",-1)) );
      }
      it->setText( path.section("/",-1) );
    }

  }
  //Now add it to the widget
  ui->listWidget->addItem(it);
  if(ui->listWidget->count()>100){ searcher->StopSearch(); } //just in case
}

void MainUI::stopSearch(){
  searcher->StopSearch();
  ui->tool_stop->setVisible(false);
  ui->tool_configure->setVisible(ui->radio_files->isChecked());
  updateDefaultStatusTip();
}

void MainUI::searchMessage(QString msg){
  ui->statusbar->showMessage(msg,2000);
}

void MainUI::searchFinished(){
  ui->tool_stop->setVisible(false);
  ui->tool_configure->setVisible(ui->radio_files->isChecked());
  updateDefaultStatusTip();
}
<|endoftext|>