<commit_before>#include <Refal2.h>

namespace Refal2 {

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

const char* QualifierTag = "s";

CParser::CParser( IErrorHandler* errorHandler ):
	CDirectiveParser( errorHandler )
{
	Reset();
}

void CParser::Reset()
{
	CRuleParser::Reset();
	state = S_Initial;
}

void CParser::AddToken()
{
	switch( state ) {
		case S_Initial:
			parsingInitial();
			break;
		case S_IgnoreLine:
			parsingIgnoreLine();
			break;
		case S_Word:
			parsingWord();
			break;
		case S_WordBlank:
			parsingWordBlank();
			break;
		case S_WordBlankS:
			parsingWordBlankS();
			break;
		case S_Blank:
			parsingBlank();
			break;
		case S_Rule:
			parsingRule();
			break;
		case S_Directive:
			parsingDirective();
			break;
		case S_Qualifier:
			parsingQualifier();
			break;
		default:
			assert( false );
			break;
	}
}

void CParser::parsingInitial()
{
	if( token.type == TT_Word ) {
		CRuleParser::EndFunction(); // action
		token.Move( savedToken1 );
		state = S_Word;
	} else if( token.type == TT_Blank ) {
		state = S_Blank;
	} else if( token.type != TT_LineFeed ) {
		CRuleParser::EndFunction(); // action
		CErrorsHelper::Error( "line should begin with word or space" );
		state = S_IgnoreLine;
	}
}

void CParser::parsingIgnoreLine()
{
	if( token.type == TT_LineFeed ) {
		state = S_Initial;
	}
}

void CParser::parsingWord()
{
	if( token.type == TT_LineFeed ) {
		token.Swap( savedToken1 );
		CRuleParser::BeginFunction(); // action
		token.Swap( savedToken1 );
		state = S_Initial;
	} else if( token.type == TT_Blank ) {
		state = S_WordBlank;
	} else {
		token.Swap( savedToken1 );
		CRuleParser::BeginFunction(); // action
		token.Swap( savedToken1 );
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingWordBlank()
{
	if( token.type == TT_Word
		&& CDirectiveParser::StartParseIfStartDirective( savedToken1.word ) )
	{
		state = S_Directive;
	} else if( wordIs( QualifierTag ) ) {
		token.Move( savedToken2 );
		state = S_WordBlankS;
	} else {
		token.Swap( savedToken1 );
		CRuleParser::BeginFunction(); // action
		token.Swap( savedToken1 );
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingWordBlankS()
{
	if( token.type == TT_Blank ) {
		token.Swap( savedToken1 );
		CQualifierParser::StartNamedQualifier();
		state = IsWrong() ? S_IgnoreLine : S_Qualifier;
		token.Swap( savedToken1 );
	} else {
		token.Swap( savedToken1 );
		CRuleParser::BeginFunction(); // action
		token.Swap( savedToken1 );
		state = S_Rule;
		savedToken2.Swap( token );
		AddToken(); // QualifierTag
		savedToken2.Move( token );
		AddToken(); // current token
	}
}

void CParser::parsingBlank()
{
	if( token.type == TT_Word && CDirectiveParser::StartParseIfDirective() ) {
		CRuleParser::EndFunction(); // action
		state = S_Directive;
		return;
	}
	CRuleParser::BeginRule();
	state = S_Rule;
	AddToken();
}

void CParser::parsingQualifier()
{
	CQualifierParser::AddToken();
	checkFinished();
}

void CParser::parsingRule()
{
	CRuleParser::AddToken();
	checkFinished();
}

void CParser::parsingDirective()
{
	CDirectiveParser::AddToken();
	checkFinished();
}

void CParser::checkFinished()
{
	if( IsCorrect() ) {
		state = S_Initial;
	} else if( IsWrong() ) {
		state = S_IgnoreLine;
		AddToken();
	}
}

bool CParser::wordIs( const std::string& value ) const
{
	if( token.type == TT_Word ) {
		std::string lowerWord( token.word );
		MakeLower( lowerWord );
		return ( lowerWord == value );
	}
	return false;
}

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

} // end of namespace Refal2
<commit_msg>small changes<commit_after>#include <Refal2.h>

namespace Refal2 {

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

const char* QualifierTag = "s";

CParser::CParser( IErrorHandler* errorHandler ):
	CDirectiveParser( errorHandler )
{
	Reset();
}

void CParser::Reset()
{
	CRuleParser::Reset();
	state = S_Initial;
}

void CParser::AddToken()
{
	switch( state ) {
		case S_Initial:
			parsingInitial();
			break;
		case S_IgnoreLine:
			parsingIgnoreLine();
			break;
		case S_Word:
			parsingWord();
			break;
		case S_WordBlank:
			parsingWordBlank();
			break;
		case S_WordBlankS:
			parsingWordBlankS();
			break;
		case S_Blank:
			parsingBlank();
			break;
		case S_Rule:
			parsingRule();
			break;
		case S_Directive:
			parsingDirective();
			break;
		case S_Qualifier:
			parsingQualifier();
			break;
		default:
			assert( false );
			break;
	}
}

void CParser::parsingInitial()
{
	if( token.type == TT_Word ) {
		CRuleParser::EndFunction(); // action
		token.Move( savedToken1 );
		state = S_Word;
	} else if( token.type == TT_Blank ) {
		state = S_Blank;
	} else if( token.type != TT_LineFeed ) {
		CRuleParser::EndFunction(); // action
		CErrorsHelper::Error( "line should begin with word or space" );
		state = S_IgnoreLine;
	}
}

void CParser::parsingIgnoreLine()
{
	if( token.type == TT_LineFeed ) {
		state = S_Initial;
	}
}

void CParser::parsingWord()
{
	if( token.type == TT_LineFeed ) {
		token.Swap( savedToken1 );
		CRuleParser::BeginFunction(); // action
		token.Swap( savedToken1 );
		state = S_Initial;
	} else if( token.type == TT_Blank ) {
		state = S_WordBlank;
	} else {
		token.Swap( savedToken1 );
		CRuleParser::BeginFunction(); // action
		token.Swap( savedToken1 );
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingWordBlank()
{
	if( token.type == TT_Word
		&& CDirectiveParser::StartParseIfStartDirective( savedToken1.word ) )
	{
		state = S_Directive;
	} else if( wordIs( QualifierTag ) ) {
		token.Move( savedToken2 );
		state = S_WordBlankS;
	} else {
		token.Swap( savedToken1 );
		CRuleParser::BeginFunction(); // action
		token.Swap( savedToken1 );
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingWordBlankS()
{
	if( token.type == TT_Blank ) {
		token.Swap( savedToken1 );
		CQualifierParser::StartNamedQualifier();
		state = IsWrong() ? S_IgnoreLine : S_Qualifier;
		token.Swap( savedToken1 );
	} else {
		token.Swap( savedToken1 );
		CRuleParser::BeginFunction(); // action
		token.Swap( savedToken1 );
		state = S_Rule;
		savedToken2.Swap( token );
		AddToken(); // QualifierTag
		savedToken2.Move( token );
		AddToken(); // current token
	}
}

void CParser::parsingBlank()
{
	if( token.type == TT_Word && CDirectiveParser::StartParseIfDirective() ) {
		CRuleParser::EndFunction(); // action
		state = S_Directive;
	} else {
		CRuleParser::BeginRule();
		state = S_Rule;
		AddToken();
	}
}

void CParser::parsingQualifier()
{
	CQualifierParser::AddToken();
	checkFinished();
}

void CParser::parsingRule()
{
	CRuleParser::AddToken();
	checkFinished();
}

void CParser::parsingDirective()
{
	CDirectiveParser::AddToken();
	checkFinished();
}

void CParser::checkFinished()
{
	if( IsCorrect() ) {
		state = S_Initial;
	} else if( IsWrong() ) {
		state = S_IgnoreLine;
		AddToken();
	}
}

bool CParser::wordIs( const std::string& value ) const
{
	if( token.type == TT_Word ) {
		std::string lowerWord( token.word );
		MakeLower( lowerWord );
		return ( lowerWord == value );
	}
	return false;
}

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

} // end of namespace Refal2
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2019, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. Neither the name of the copyright holder 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 "platform/openthread-posix-config.h"

#include "cli/cli_config.h"

#include <openthread/platform/toolchain.h>

#ifndef HAVE_LIBEDIT
#define HAVE_LIBEDIT 0
#endif

#ifndef HAVE_LIBREADLINE
#define HAVE_LIBREADLINE 0
#endif

#define OPENTHREAD_USE_READLINE (HAVE_LIBEDIT || HAVE_LIBREADLINE)

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>

#if HAVE_LIBEDIT
#include <editline/readline.h>
#elif HAVE_LIBREADLINE
#include <readline/history.h>
#include <readline/readline.h>
#endif

#include "common/code_utils.hpp"

#include "platform-posix.h"

enum
{
    kLineBufferSize = OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH,
};

static_assert(kLineBufferSize >= sizeof("> "), "kLineBufferSize is too small");
static_assert(kLineBufferSize >= sizeof("Done\r\n"), "kLineBufferSize is too small");
static_assert(kLineBufferSize >= sizeof("Error "), "kLineBufferSize is too small");

static int sSessionFd = -1;

#if OPENTHREAD_USE_READLINE
static void InputCallback(char *aLine)
{
    if (aLine != nullptr)
    {
        add_history(aLine);
        dprintf(sSessionFd, "%s\n", aLine);
        free(aLine);
    }
    else
    {
        exit(OT_EXIT_SUCCESS);
    }
}
#endif // OPENTHREAD_USE_READLINE

static bool DoWrite(int aFile, const void *aBuffer, size_t aSize)
{
    bool ret = true;

    while (aSize)
    {
        ssize_t rval = write(aFile, aBuffer, aSize);
        if (rval <= 0)
        {
            VerifyOrExit((rval == -1) && (errno == EINTR), perror("write"); ret = false);
        }
        else
        {
            aBuffer = reinterpret_cast<const uint8_t *>(aBuffer) + rval;
            aSize -= static_cast<size_t>(rval);
        }
    }

exit:
    return ret;
}

static int ConnectSession(void)
{
    int ret;

    if (sSessionFd != -1)
    {
        close(sSessionFd);
    }

    sSessionFd = socket(AF_UNIX, SOCK_STREAM, 0);
    VerifyOrExit(sSessionFd != -1, ret = -1);

    {
        struct sockaddr_un sockname;

        memset(&sockname, 0, sizeof(struct sockaddr_un));
        sockname.sun_family = AF_UNIX;
        strncpy(sockname.sun_path, OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, sizeof(sockname.sun_path) - 1);

        ret = connect(sSessionFd, reinterpret_cast<const struct sockaddr *>(&sockname), sizeof(struct sockaddr_un));
    }

exit:
    return ret;
}

static bool ReconnectSession(void)
{
    bool     ok    = false;
    uint32_t delay = 0; // 100ms

    for (int i = 0; i < 6; i++) // delay for 3.1s in total
    {
        int rval;

        usleep(delay);
        delay = delay > 0 ? delay * 2 : 100000;

        rval = ConnectSession();

        VerifyOrExit(rval == -1, ok = true);

        // Exit immediately if the sock file is not found
        VerifyOrExit(errno != ENOENT);
    }

exit:
    return ok;
}

int main(int argc, char *argv[])
{
    bool   isInteractive = true;
    bool   isFinished    = false;
    bool   isBeginOfLine = true;
    char   lineBuffer[kLineBufferSize];
    size_t lineBufferWritePos = 0;
    int    ret;

    VerifyOrExit(ConnectSession() != -1, perror("connect session failed"); ret = OT_EXIT_FAILURE);

    if (argc > 1)
    {
        char   buffer[kLineBufferSize];
        size_t count = 0;

        for (int i = 1; i < argc; i++)
        {
            int rval = snprintf(&buffer[count], (sizeof(buffer) - count), "%s ", argv[i]);

            VerifyOrExit(rval > 0 && static_cast<size_t>(rval) < (sizeof(buffer) - count), ret = OT_EXIT_FAILURE);
            count += static_cast<size_t>(rval);
        }

        // replace the trailing space with newline
        buffer[count - 1] = '\n';
        VerifyOrExit(DoWrite(sSessionFd, buffer, count), ret = OT_EXIT_FAILURE);

        isInteractive = false;
    }
#if OPENTHREAD_USE_READLINE
    else
    {
        rl_instream           = stdin;
        rl_outstream          = stdout;
        rl_inhibit_completion = true;
        rl_callback_handler_install("> ", InputCallback);
        rl_already_prompted = 1;
    }
#endif

    while (!isFinished)
    {
        char   buffer[kLineBufferSize];
        fd_set readFdSet;
        int    maxFd = sSessionFd;

        FD_ZERO(&readFdSet);

        FD_SET(sSessionFd, &readFdSet);

        if (isInteractive)
        {
            FD_SET(STDIN_FILENO, &readFdSet);
            if (STDIN_FILENO > maxFd)
            {
                maxFd = STDIN_FILENO;
            }
        }

        ret = select(maxFd + 1, &readFdSet, nullptr, nullptr, nullptr);

        VerifyOrExit(ret != -1, perror("select"); ret = OT_EXIT_FAILURE);

        if (ret == 0)
        {
            ExitNow(ret = OT_EXIT_SUCCESS);
        }

        if (isInteractive && FD_ISSET(STDIN_FILENO, &readFdSet))
        {
#if OPENTHREAD_USE_READLINE
            rl_callback_read_char();
#else
            VerifyOrExit(fgets(buffer, sizeof(buffer), stdin) != nullptr, ret = OT_EXIT_FAILURE);

            VerifyOrExit(DoWrite(sSessionFd, buffer, strlen(buffer)), ret = OT_EXIT_FAILURE);
#endif
        }

        if (FD_ISSET(sSessionFd, &readFdSet))
        {
            ssize_t rval = read(sSessionFd, buffer, sizeof(buffer));
            VerifyOrExit(rval != -1, perror("read"); ret = OT_EXIT_FAILURE);

            if (rval == 0)
            {
                // daemon closed sSessionFd
                if (isInteractive && ReconnectSession())
                {
                    continue;
                }

                ExitNow(ret = isInteractive ? OT_EXIT_FAILURE : OT_EXIT_SUCCESS);
            }

            if (isInteractive)
            {
                VerifyOrExit(DoWrite(STDOUT_FILENO, buffer, static_cast<size_t>(rval)), ret = OT_EXIT_FAILURE);
            }
            else
            {
                for (ssize_t i = 0; i < rval; i++)
                {
                    char c = buffer[i];

                    lineBuffer[lineBufferWritePos++] = c;
                    if (c == '\n' || lineBufferWritePos >= sizeof(lineBuffer) - 1)
                    {
                        char * line = lineBuffer;
                        size_t len  = lineBufferWritePos;

                        // read one line successfully or line buffer is full
                        line[len] = '\0';

                        if (isBeginOfLine && strncmp("> ", lineBuffer, 2) == 0)
                        {
                            line += 2;
                            len -= 2;
                        }

                        VerifyOrExit(DoWrite(STDOUT_FILENO, line, len), ret = OT_EXIT_FAILURE);

                        if (isBeginOfLine && (strncmp("Done\n", line, 5) == 0 || strncmp("Done\r\n", line, 6) == 0 ||
                                              strncmp("Error ", line, 6) == 0))
                        {
                            isFinished = true;
                            ret        = OT_EXIT_SUCCESS;
                            break;
                        }

                        // reset for next line
                        lineBufferWritePos = 0;
                        isBeginOfLine      = c == '\n';
                    }
                }
            }
        }
    }

exit:
    if (sSessionFd != -1)
    {
#if OPENTHREAD_USE_READLINE
        if (isInteractive)
        {
            rl_callback_handler_remove();
        }
#endif
        close(sSessionFd);
    }

    return ret;
}
<commit_msg>[posix] escape CLI arguments (#6556)<commit_after>/*
 *  Copyright (c) 2019, The OpenThread Authors.
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions are met:
 *  1. Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *  2. 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.
 *  3. Neither the name of the copyright holder 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 "platform/openthread-posix-config.h"

#include "cli/cli_config.h"

#include <openthread/platform/toolchain.h>

#ifndef HAVE_LIBEDIT
#define HAVE_LIBEDIT 0
#endif

#ifndef HAVE_LIBREADLINE
#define HAVE_LIBREADLINE 0
#endif

#define OPENTHREAD_USE_READLINE (HAVE_LIBEDIT || HAVE_LIBREADLINE)

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <time.h>
#include <unistd.h>

#if HAVE_LIBEDIT
#include <editline/readline.h>
#elif HAVE_LIBREADLINE
#include <readline/history.h>
#include <readline/readline.h>
#endif

#include "common/code_utils.hpp"

#include "platform-posix.h"

enum
{
    kLineBufferSize = OPENTHREAD_CONFIG_CLI_MAX_LINE_LENGTH,
};

static_assert(kLineBufferSize >= sizeof("> "), "kLineBufferSize is too small");
static_assert(kLineBufferSize >= sizeof("Done\r\n"), "kLineBufferSize is too small");
static_assert(kLineBufferSize >= sizeof("Error "), "kLineBufferSize is too small");

static int sSessionFd = -1;

#if OPENTHREAD_USE_READLINE
static void InputCallback(char *aLine)
{
    if (aLine != nullptr)
    {
        add_history(aLine);
        dprintf(sSessionFd, "%s\n", aLine);
        free(aLine);
    }
    else
    {
        exit(OT_EXIT_SUCCESS);
    }
}
#endif // OPENTHREAD_USE_READLINE

static bool DoWrite(int aFile, const void *aBuffer, size_t aSize)
{
    bool ret = true;

    while (aSize)
    {
        ssize_t rval = write(aFile, aBuffer, aSize);
        if (rval <= 0)
        {
            VerifyOrExit((rval == -1) && (errno == EINTR), perror("write"); ret = false);
        }
        else
        {
            aBuffer = reinterpret_cast<const uint8_t *>(aBuffer) + rval;
            aSize -= static_cast<size_t>(rval);
        }
    }

exit:
    return ret;
}

static int ConnectSession(void)
{
    int ret;

    if (sSessionFd != -1)
    {
        close(sSessionFd);
    }

    sSessionFd = socket(AF_UNIX, SOCK_STREAM, 0);
    VerifyOrExit(sSessionFd != -1, ret = -1);

    {
        struct sockaddr_un sockname;

        memset(&sockname, 0, sizeof(struct sockaddr_un));
        sockname.sun_family = AF_UNIX;
        strncpy(sockname.sun_path, OPENTHREAD_POSIX_DAEMON_SOCKET_NAME, sizeof(sockname.sun_path) - 1);

        ret = connect(sSessionFd, reinterpret_cast<const struct sockaddr *>(&sockname), sizeof(struct sockaddr_un));
    }

exit:
    return ret;
}

static bool ReconnectSession(void)
{
    bool     ok    = false;
    uint32_t delay = 0; // 100ms

    for (int i = 0; i < 6; i++) // delay for 3.1s in total
    {
        int rval;

        usleep(delay);
        delay = delay > 0 ? delay * 2 : 100000;

        rval = ConnectSession();

        VerifyOrExit(rval == -1, ok = true);

        // Exit immediately if the sock file is not found
        VerifyOrExit(errno != ENOENT);
    }

exit:
    return ok;
}

static bool IsSeparator(char aChar)
{
    return (aChar == ' ') || (aChar == '\t') || (aChar == '\r') || (aChar == '\n');
}

int main(int argc, char *argv[])
{
    bool   isInteractive = true;
    bool   isFinished    = false;
    bool   isBeginOfLine = true;
    char   lineBuffer[kLineBufferSize];
    size_t lineBufferWritePos = 0;
    int    ret;

    VerifyOrExit(ConnectSession() != -1, perror("connect session failed"); ret = OT_EXIT_FAILURE);

    if (argc > 1)
    {
        char   buffer[kLineBufferSize];
        size_t count = 0;

        for (int i = 1; i < argc; i++)
        {
            for (const char *c = argv[i]; *c; ++c)
            {
                if (IsSeparator(*c))
                {
                    buffer[count++] = '\\';
                }
                buffer[count++] = *c;
            }
            buffer[count++] = ' ';
        }

        // replace the trailing space with newline
        buffer[count - 1] = '\n';
        VerifyOrExit(DoWrite(sSessionFd, buffer, count), ret = OT_EXIT_FAILURE);

        isInteractive = false;
    }
#if OPENTHREAD_USE_READLINE
    else
    {
        rl_instream           = stdin;
        rl_outstream          = stdout;
        rl_inhibit_completion = true;
        rl_callback_handler_install("> ", InputCallback);
        rl_already_prompted = 1;
    }
#endif

    while (!isFinished)
    {
        char   buffer[kLineBufferSize];
        fd_set readFdSet;
        int    maxFd = sSessionFd;

        FD_ZERO(&readFdSet);

        FD_SET(sSessionFd, &readFdSet);

        if (isInteractive)
        {
            FD_SET(STDIN_FILENO, &readFdSet);
            if (STDIN_FILENO > maxFd)
            {
                maxFd = STDIN_FILENO;
            }
        }

        ret = select(maxFd + 1, &readFdSet, nullptr, nullptr, nullptr);

        VerifyOrExit(ret != -1, perror("select"); ret = OT_EXIT_FAILURE);

        if (ret == 0)
        {
            ExitNow(ret = OT_EXIT_SUCCESS);
        }

        if (isInteractive && FD_ISSET(STDIN_FILENO, &readFdSet))
        {
#if OPENTHREAD_USE_READLINE
            rl_callback_read_char();
#else
            VerifyOrExit(fgets(buffer, sizeof(buffer), stdin) != nullptr, ret = OT_EXIT_FAILURE);

            VerifyOrExit(DoWrite(sSessionFd, buffer, strlen(buffer)), ret = OT_EXIT_FAILURE);
#endif
        }

        if (FD_ISSET(sSessionFd, &readFdSet))
        {
            ssize_t rval = read(sSessionFd, buffer, sizeof(buffer));
            VerifyOrExit(rval != -1, perror("read"); ret = OT_EXIT_FAILURE);

            if (rval == 0)
            {
                // daemon closed sSessionFd
                if (isInteractive && ReconnectSession())
                {
                    continue;
                }

                ExitNow(ret = isInteractive ? OT_EXIT_FAILURE : OT_EXIT_SUCCESS);
            }

            if (isInteractive)
            {
                VerifyOrExit(DoWrite(STDOUT_FILENO, buffer, static_cast<size_t>(rval)), ret = OT_EXIT_FAILURE);
            }
            else
            {
                for (ssize_t i = 0; i < rval; i++)
                {
                    char c = buffer[i];

                    lineBuffer[lineBufferWritePos++] = c;
                    if (c == '\n' || lineBufferWritePos >= sizeof(lineBuffer) - 1)
                    {
                        char * line = lineBuffer;
                        size_t len  = lineBufferWritePos;

                        // read one line successfully or line buffer is full
                        line[len] = '\0';

                        if (isBeginOfLine && strncmp("> ", lineBuffer, 2) == 0)
                        {
                            line += 2;
                            len -= 2;
                        }

                        VerifyOrExit(DoWrite(STDOUT_FILENO, line, len), ret = OT_EXIT_FAILURE);

                        if (isBeginOfLine && (strncmp("Done\n", line, 5) == 0 || strncmp("Done\r\n", line, 6) == 0 ||
                                              strncmp("Error ", line, 6) == 0))
                        {
                            isFinished = true;
                            ret        = OT_EXIT_SUCCESS;
                            break;
                        }

                        // reset for next line
                        lineBufferWritePos = 0;
                        isBeginOfLine      = c == '\n';
                    }
                }
            }
        }
    }

exit:
    if (sSessionFd != -1)
    {
#if OPENTHREAD_USE_READLINE
        if (isInteractive)
        {
            rl_callback_handler_remove();
        }
#endif
        close(sSessionFd);
    }

    return ret;
}
<|endoftext|>


<commit_before>#include <sirius.h>

void test1(void)
{
    printf("\n");
    printf("split 17 elements between 4 ranks\n");
    printf("\n");
    for (int i = 0; i < 4; i++)
    {
        splindex<block> spl(17, 4, i);
        printf("rank : %i, local size : %i\n", i, spl.local_size());

        printf("local index and rank for each element:\n");
        for (int k = 0; k < 17; k++)
        {
            int iloc = spl.location(_splindex_offs_, k);
            int rank = spl.location(_splindex_rank_, k);
            printf(" global index : %i => local index : %i, rank: %i\n", k, iloc, rank);
        }
    }
}

void test1a(void)
{
    printf("\n");
    printf("split 17 elements between 4 ranks in block-cyclic distribution\n");
    printf("\n");
    for (int i = 0; i < 4; i++)
    {
        splindex<block_cyclic> spl(17, 4, i, 2);
        printf("rank : %i, local size : %i\n", i, spl.local_size());

        printf("local index and rank for each element:\n");
        for (int k = 0; k < 17; k++)
        {
            int iloc = spl.location(_splindex_offs_, k);
            int rank = spl.location(_splindex_rank_, k);
            printf(" global index : %i => local index : %i, rank: %i\n", k, iloc, rank);
        }
    }
}

void test2()
{
    printf("\n");
    printf("test2\n");

    for (int i = 0; i < 4; i++)
    {
        printf("rank : %i\n", i);
        splindex<block> spl(17, 4, i);

        #pragma omp parallel
        for (auto it = splindex_iterator<block>(spl); it.valid(); it++)
        {
            #pragma omp flush
            printf("thread_id: %i, local index : %i, global index : %i\n", Platform::thread_id(), it.idx_local(), it.idx());
        }
    }

}

void test3()
{
    printf("\n");
    printf("test3\n");
    for (int num_ranks = 1; num_ranks < 17; num_ranks++)
    {
        for (int N = 1; N < 113; N++)
        {
            splindex<block> spl(N, num_ranks);
            int sz = 0;
            for (int i = 0; i < num_ranks; i++) sz += spl.local_size(i);
            if (sz != N)
            {
                std::cout << "wrong sum of local sizes" << std::endl;
                exit(0);
            }
            for (int i = 0; i < N; i++)
            {
                int rank = spl.location(_splindex_rank_, i);
                int offset = spl.location(_splindex_offs_, i);
                if (i != spl.global_index(offset, rank))
                {
                    std::cout << "wrong index" << std::endl;
                    exit(0);
                }
            }
        }
    }
}

void test4()
{
    printf("\n");
    printf("test4\n");
    for (int bs = 1; bs < 17; bs++)
    {
        for (int num_ranks = 1; num_ranks < 13; num_ranks++)
        {
            for (int N = 1; N < 1113; N++)
            {
                splindex<block_cyclic> spl(N, num_ranks, bs);
                int sz = 0;
                for (int i = 0; i < num_ranks; i++) sz += spl.local_size(i);
                if (sz != N)
                {
                    std::cout << "wrong sum of local sizes" << std::endl;
                    exit(0);
                }

                for (int i = 0; i < N; i++)
                {
                    int rank = spl.location(_splindex_rank_, i);
                    int offset = spl.location(_splindex_offs_, i);
                    if (i != spl.global_index(offset, rank))
                    {
                        std::cout << "wrong index" << std::endl;
                        std::cout << "bs = " << bs << std::endl
                                  << "num_ranks =  " << num_ranks << std::endl
                                  << "N = " << N << std::endl
                                  << "idx = " << i << std::endl
                                  << "rank = " << rank << std::endl
                                  << "offset = " << offset << std::endl
                                  << "computed index = " << spl.global_index(offset, rank) << std::endl;
                        exit(0);
                    }
                }
            }
        }
    }
}

int main(int argn, char** argv)
{
    test1();
    test1a();
    test2();
    test3();
    test4();
}
<commit_msg>update of splindex test<commit_after>#include <sirius.h>

void test1(void)
{
    printf("\n");
    printf("split 17 elements between 4 ranks\n");
    printf("\n");
    for (int i = 0; i < 4; i++)
    {
        splindex<block> spl(17, 4, i);
        printf("rank : %i, local size : %i\n", i, spl.local_size());

        printf("local index and rank for each element:\n");
        for (int k = 0; k < 17; k++)
        {
            int iloc = spl.location(_splindex_offs_, k);
            int rank = spl.location(_splindex_rank_, k);
            printf(" global index : %i => local index : %i, rank: %i\n", k, iloc, rank);
        }
    }
}

void test1a(void)
{
    printf("\n");
    printf("split 17 elements between 4 ranks in block-cyclic distribution\n");
    printf("\n");
    splindex<block_cyclic>::set_cyclic_block_size(2);
    for (int i = 0; i < 4; i++)
    {
        splindex<block_cyclic> spl(17, 4, i);
        printf("rank : %i, local size : %i\n", i, spl.local_size());

        printf("local index and rank for each element:\n");
        for (int k = 0; k < 17; k++)
        {
            int iloc = spl.location(_splindex_offs_, k);
            int rank = spl.location(_splindex_rank_, k);
            printf(" global index : %i => local index : %i, rank: %i\n", k, iloc, rank);
        }
    }
}

void test2()
{
    printf("\n");
    printf("test2\n");

    for (int i = 0; i < 4; i++)
    {
        printf("rank : %i\n", i);
        splindex<block> spl(17, 4, i);

        #pragma omp parallel
        for (auto it = splindex_iterator<block>(spl); it.valid(); it++)
        {
            #pragma omp flush
            printf("thread_id: %i, local index : %i, global index : %i\n", Platform::thread_id(), it.idx_local(), it.idx());
        }
    }

}

void test3()
{
    printf("\n");
    printf("test3\n");
    for (int num_ranks = 1; num_ranks < 17; num_ranks++)
    {
        for (int N = 0; N < 113; N++)
        {
            splindex<block> spl(N, num_ranks, 0);
            int sz = 0;
            for (int i = 0; i < num_ranks; i++) sz += spl.local_size(i);
            if (sz != N)
            {
                std::cout << "wrong sum of local sizes" << std::endl;
                exit(0);
            }
            for (int i = 0; i < N; i++)
            {
                int rank = spl.location(_splindex_rank_, i);
                int offset = spl.location(_splindex_offs_, i);
                if (i != spl.global_index(offset, rank))
                {
                    std::cout << "wrong index" << std::endl;
                    exit(0);
                }
            }
        }
    }
}

void test4()
{
    printf("\n");
    printf("test4\n");
    for (int bs = 1; bs < 17; bs++)
    {
        splindex<block_cyclic>::set_cyclic_block_size(bs);
        for (int num_ranks = 1; num_ranks < 13; num_ranks++)
        {
            for (int N = 1; N < 1113; N++)
            {
                splindex<block_cyclic> spl(N, num_ranks, 0);
                int sz = 0;
                for (int i = 0; i < num_ranks; i++) sz += spl.local_size(i);
                if (sz != N)
                {
                    std::cout << "wrong sum of local sizes" << std::endl;
                    exit(0);
                }

                for (int i = 0; i < N; i++)
                {
                    int rank = spl.location(_splindex_rank_, i);
                    int offset = spl.location(_splindex_offs_, i);
                    if (i != spl.global_index(offset, rank))
                    {
                        std::cout << "wrong index" << std::endl;
                        std::cout << "bs = " << bs << std::endl
                                  << "num_ranks =  " << num_ranks << std::endl
                                  << "N = " << N << std::endl
                                  << "idx = " << i << std::endl
                                  << "rank = " << rank << std::endl
                                  << "offset = " << offset << std::endl
                                  << "computed index = " << spl.global_index(offset, rank) << std::endl;
                        exit(0);
                    }
                }
            }
        }
    }
}

int main(int argn, char** argv)
{
    Platform::initialize(1);
    test1();
    test1a();
    test2();
    test3();
    test4();
    Platform::finalize();
}
<|endoftext|>


<commit_before>#include "Scene.hpp"

Scene::Scene(){
    broadphase = new btDbvtBroadphase();
    collisionConfiguration = new btDefaultCollisionConfiguration();
    dispatcher = new btCollisionDispatcher(collisionConfiguration);
    solver = new btSequentialImpulseConstraintSolver;
    dynamicsWorld = new btDiscreteDynamicsWorld(dispatcher,broadphase,solver,collisionConfiguration);

    dynamicsWorld->setGravity(btVector3(0,-9.81f,0));

    objects = new SceneGameObjectLists();
}
Scene::~Scene(){
    delete broadphase;
    delete collisionConfiguration;
    delete dispatcher;
    delete solver;
    delete dynamicsWorld;
    delete objects;
}
void Scene::drawAllGameObjects(const GLuint mat_location){
    GameObject* obj;
    for (int i = 0; i < objects->size(); i++){
        obj = this->objects->get(i);
        if (obj != nullptr){
            obj->draw(mat_location);
        }else{
            printf("ES NULLLL");
        }

    }
}
void Scene::addGameObject(GameObject* obj){
    this->objects->addGameObject(obj);
    this->dynamicsWorld->addRigidBody(obj->getRigidBody());
}
void Scene::stepSimulation(float freq, int algo){
    this->dynamicsWorld->stepSimulation(freq, algo);
}
btDiscreteDynamicsWorld* Scene::getDynamicsWorld(){
    return this->dynamicsWorld;
}
<commit_msg>Delete scene.cpp<commit_after><|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the FOO module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qticonloader.h"
#include <QtGui/QPixmapCache>

#include <QtCore/QList>
#include <QtCore/QHash>
#include <QtCore/QDir>
#include <QtCore/QString>
#include <QtCore/QLibrary>
#include <QtCore/QSettings>
#include <QtCore/QTextStream>

#ifdef Q_WS_X11

class QIconTheme
{
public:
    QIconTheme(QHash <int, QString> dirList, QStringList parents) :
            _dirList(dirList), _parents(parents), _valid(true){ }
    QIconTheme() : _valid(false){ }
    QHash <int, QString> dirList() {return _dirList;}
    QStringList parents() {return _parents;}
    bool isValid() {return _valid;}

private:
    QHash <int, QString> _dirList;
    QStringList _parents;
    bool _valid;
};

class QtIconLoaderImplementation
{
public:
    QtIconLoaderImplementation();
    QString findIcon(int size, const QString &name) const;

private:
    QIconTheme parseIndexFile(const QString &themeName) const;
    void lookupIconTheme() const;
    QString findIconHelper(int size,
                           const QString &themeName,
                           const QString &iconName,
                           QStringList &visited) const;
    mutable QString themeName;
    mutable QStringList iconDirs;
    mutable QHash <QString, QIconTheme> themeList;
};

Q_GLOBAL_STATIC(QtIconLoaderImplementation, iconLoaderInstance)
#endif

/*!

    Returns the standard icon for the given icon /a name
    as specified in the freedesktop icon spec
    http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html

    /a fallback is an optional argument to specify the icon to be used if
    no icon is found on the platform. This is particularily useful for
    crossplatform code.

*/
QString QtIconLoader::icon(const QString &name)
{
    // fast path: check if it exists as-is
    if (QFile::exists(name))
        return name;
#ifdef Q_WS_X11
    QString pngExtension(QLatin1String(".png"));
    QList<int> iconSizes;
    iconSizes << 64 << 48 << 32 << 24 << 16;
    Q_FOREACH (int size, iconSizes) {
        QString path = iconLoaderInstance()->findIcon(size, name + pngExtension);
        if (!path.isEmpty())
            return path;
    }
#endif
    Q_UNUSED(name);
    return QString();
}

#ifdef Q_WS_X11

QtIconLoaderImplementation::QtIconLoaderImplementation()
{
    lookupIconTheme();
}

extern "C" {
    struct GConfClient;
    struct GError;
    typedef void (*Ptr_g_type_init)();
    typedef GConfClient* (*Ptr_gconf_client_get_default)();
    typedef char* (*Ptr_gconf_client_get_string)(GConfClient*, const char*, GError **);
    typedef void (*Ptr_g_object_unref)(void *);
    typedef void (*Ptr_g_error_free)(GError *);
    typedef void (*Ptr_g_free)(void*);
    static Ptr_g_type_init p_g_type_init = 0;
    static Ptr_gconf_client_get_default p_gconf_client_get_default = 0;
    static Ptr_gconf_client_get_string p_gconf_client_get_string = 0;
    static Ptr_g_object_unref p_g_object_unref = 0;
    static Ptr_g_error_free p_g_error_free = 0;
    static Ptr_g_free p_g_free = 0;
}

static int kdeVersion()
{
    static int version = qgetenv("KDE_SESSION_VERSION").toInt();
    return version;
}

static QString kdeHome()
{
    static QString kdeHomePath;
    if (kdeHomePath.isEmpty()) {
        kdeHomePath = QFile::decodeName(qgetenv("KDEHOME"));
        if (kdeHomePath.isEmpty()) {
            int kdeSessionVersion = kdeVersion();
            QDir homeDir(QDir::homePath());
            QString kdeConfDir(QLatin1String("/.kde"));
            if (4 == kdeSessionVersion && homeDir.exists(QLatin1String(".kde4")))
                kdeConfDir = QLatin1String("/.kde4");
            kdeHomePath = QDir::homePath() + kdeConfDir;
        }
    }
    return kdeHomePath;
}

void QtIconLoaderImplementation::lookupIconTheme() const
{

#ifdef Q_WS_X11
    QString dataDirs = QFile::decodeName(getenv("XDG_DATA_DIRS"));
    if (dataDirs.isEmpty())
        dataDirs = QLatin1String("/usr/local/share/:/usr/share/");

    dataDirs.prepend(QDir::homePath() + QLatin1String("/:"));
    iconDirs = dataDirs.split(QLatin1Char(':'));

    // If we are running GNOME we resolve and use GConf. In all other
    // cases we currently use the KDE icon theme

    if (qgetenv("DESKTOP_SESSION") == "gnome" ||
        !qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) {

        if (themeName.isEmpty()) {
            // Resolve glib and gconf

            p_g_type_init =              (Ptr_g_type_init)QLibrary::resolve(QLatin1String("gobject-2.0"), 0, "g_type_init");
            p_gconf_client_get_default = (Ptr_gconf_client_get_default)QLibrary::resolve(QLatin1String("gconf-2"), 4, "gconf_client_get_default");
            p_gconf_client_get_string =  (Ptr_gconf_client_get_string)QLibrary::resolve(QLatin1String("gconf-2"), 4, "gconf_client_get_string");
            p_g_object_unref =           (Ptr_g_object_unref)QLibrary::resolve(QLatin1String("gobject-2.0"), 0, "g_object_unref");
            p_g_error_free =             (Ptr_g_error_free)QLibrary::resolve(QLatin1String("glib-2.0"), 0, "g_error_free");
            p_g_free =                   (Ptr_g_free)QLibrary::resolve(QLatin1String("glib-2.0"), 0, "g_free");

            if (p_g_type_init && p_gconf_client_get_default &&
                p_gconf_client_get_string && p_g_object_unref &&
                p_g_error_free && p_g_free) {

                p_g_type_init();
                GConfClient* client = p_gconf_client_get_default();
                GError *err = 0;

                char *str = p_gconf_client_get_string(client, "/desktop/gnome/interface/icon_theme", &err);
                if (!err) {
                    themeName = QString::fromUtf8(str);
                    p_g_free(str);
                }

                p_g_object_unref(client);
                if (err)
                    p_g_error_free (err);
            }
            if (themeName.isEmpty())
                themeName = QLatin1String("gnome");
        }

        if (!themeName.isEmpty())
            return;
    }

    // KDE (and others)
    if (dataDirs.isEmpty())
        dataDirs = QLatin1String("/usr/local/share/:/usr/share/");

    dataDirs += QLatin1Char(':') + kdeHome() + QLatin1String("/share");
    dataDirs.prepend(QDir::homePath() + QLatin1String("/:"));
    QStringList kdeDirs = QFile::decodeName(getenv("KDEDIRS")).split(QLatin1Char(':'));
    Q_FOREACH (const QString dirName, kdeDirs)
        dataDirs.append(QLatin1Char(':') + dirName + QLatin1String("/share"));
    iconDirs = dataDirs.split(QLatin1Char(':'));

    QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde"));
    QDir dir(fileInfo.canonicalFilePath());
    QString kdeDefault = kdeVersion() >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg");
    QString defaultTheme = fileInfo.exists() ? dir.dirName() : kdeDefault;
    QSettings settings(kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat);
    settings.beginGroup(QLatin1String("Icons"));
    themeName = settings.value(QLatin1String("Theme"), defaultTheme).toString();
#endif
}

QIconTheme QtIconLoaderImplementation::parseIndexFile(const QString &themeName) const
{
    QIconTheme theme;
    QFile themeIndex;
    QStringList parents;
    QHash <int, QString> dirList;

    for ( int i = 0 ; i < iconDirs.size() && !themeIndex.exists() ; ++i) {
        const QString &contentDir = QLatin1String(iconDirs[i].startsWith(QDir::homePath()) ? "/.icons/" : "/icons/");
        themeIndex.setFileName(iconDirs[i] + contentDir + themeName + QLatin1String("/index.theme"));
    }

    if (themeIndex.exists()) {
        QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
        Q_FOREACH (const QString &key, indexReader.allKeys()) {
            if (key.endsWith("/Size")) {
                if (int size = indexReader.value(key).toInt())
                    dirList.insertMulti(size, key.left(key.size() - 5));
            }
        }

        // Parent themes provide fallbacks for missing icons
        parents = indexReader.value(QLatin1String("Icon Theme/Inherits")).toStringList();
    }

    if (kdeVersion() >= 3) {
        QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde"));
        QDir dir(fileInfo.canonicalFilePath());
        QString defaultKDETheme = dir.exists() ? dir.dirName() : kdeVersion() == 3 ?
                                  QString::fromLatin1("crystalsvg") : QString::fromLatin1("oxygen");
        if (!parents.contains(defaultKDETheme) && themeName != defaultKDETheme)
            parents.append(defaultKDETheme);
    } else if (parents.isEmpty() && themeName != QLatin1String("hicolor")) {
        parents.append(QLatin1String("hicolor"));
    }

    theme = QIconTheme(dirList, parents);
    return theme;
}

QString QtIconLoaderImplementation::findIconHelper(int size, const QString &themeName,
                                                   const QString &iconName, QStringList &visited) const
{
    if (!themeName.isEmpty()) {
        visited << themeName;
        QIconTheme theme = themeList.value(themeName);

        if (!theme.isValid()) {
            theme = parseIndexFile(themeName);
            themeList.insert(themeName, theme);
        }

        if (!theme.isValid())
            return QString();

        QList <QString> subDirs = theme.dirList().values(size);
        QPixmap pixmap;

        for ( int i = 0 ; i < iconDirs.size() ; ++i) {
            for ( int j = 0 ; j < subDirs.size() ; ++j) {
                QString contentDir = (iconDirs[i].startsWith(QDir::homePath())) ?
                                     QLatin1String("/.icons/") : QLatin1String("/icons/");
                QString fileName = iconDirs[i] + contentDir + themeName + QLatin1Char('/') + subDirs[j] + QLatin1Char('/') + iconName;
                QFile file(fileName);
                pixmap = QPixmap(fileName);
                if (!pixmap.isNull())
                    return fileName;
            }
        }

        if (pixmap.isNull()) {
            QStringList parents = theme.parents();
            QString retval;
            //search recursively through inherited themes
            for (int i = 0 ; retval.isNull() && i < parents.size() ; ++i) {
                QString parentTheme = parents[i].trimmed();
                if (!visited.contains(parentTheme)) //guard against endless recursion
                    retval = findIconHelper(size, parentTheme, iconName, visited);
            }

            return retval;
        }
    }
    return QString();
}

QString QtIconLoaderImplementation::findIcon(int size, const QString &name) const
{
    if (!themeName.isEmpty()) {
        QStringList visited;
        return findIconHelper(size, themeName, name, visited);
    }
    return QString("???");
}
#endif //Q_WS_X11
<commit_msg>attempt to find the correct theme on meego<commit_after>/****************************************************************************
**
** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the FOO module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "qticonloader.h"
#include <QtGui/QPixmapCache>

#include <QtCore/QList>
#include <QtCore/QHash>
#include <QtCore/QDir>
#include <QtCore/QDebug>
#include <QtCore/QString>
#include <QtCore/QLibrary>
#include <QtCore/QSettings>
#include <QtCore/QTextStream>

#ifdef Q_WS_X11

class QIconTheme
{
public:
    QIconTheme(QHash <int, QString> dirList, QStringList parents) :
            _dirList(dirList), _parents(parents), _valid(true){ }
    QIconTheme() : _valid(false){ }
    QHash <int, QString> dirList() {return _dirList;}
    QStringList parents() {return _parents;}
    bool isValid() {return _valid;}

private:
    QHash <int, QString> _dirList;
    QStringList _parents;
    bool _valid;
};

class QtIconLoaderImplementation
{
public:
    QtIconLoaderImplementation();
    QString findIcon(int size, const QString &name) const;

private:
    QIconTheme parseIndexFile(const QString &themeName) const;
    void lookupIconTheme() const;
    QString findIconHelper(int size,
                           const QString &themeName,
                           const QString &iconName,
                           QStringList &visited) const;
    mutable QString themeName;
    mutable QStringList iconDirs;
    mutable QHash <QString, QIconTheme> themeList;
};

Q_GLOBAL_STATIC(QtIconLoaderImplementation, iconLoaderInstance)
#endif

/*!

    Returns the standard icon for the given icon /a name
    as specified in the freedesktop icon spec
    http://standards.freedesktop.org/icon-naming-spec/icon-naming-spec-latest.html

    /a fallback is an optional argument to specify the icon to be used if
    no icon is found on the platform. This is particularily useful for
    crossplatform code.

*/
QString QtIconLoader::icon(const QString &name)
{
    // fast path: check if it exists as-is
    if (QFile::exists(name))
        return name;
#ifdef Q_WS_X11
    QString pngExtension(QLatin1String(".png"));
    QList<int> iconSizes;
    iconSizes << 64 << 48 << 32 << 24 << 16;
    Q_FOREACH (int size, iconSizes) {
        QString path = iconLoaderInstance()->findIcon(size, name + pngExtension);
        if (!path.isEmpty())
            return path;
    }
#endif
    Q_UNUSED(name);
    return QString();
}

#ifdef Q_WS_X11

QtIconLoaderImplementation::QtIconLoaderImplementation()
{
    lookupIconTheme();
}

extern "C" {
    struct GConfClient;
    struct GError;
    typedef void (*Ptr_g_type_init)();
    typedef GConfClient* (*Ptr_gconf_client_get_default)();
    typedef char* (*Ptr_gconf_client_get_string)(GConfClient*, const char*, GError **);
    typedef void (*Ptr_g_object_unref)(void *);
    typedef void (*Ptr_g_free)(void*);
    static Ptr_g_type_init p_g_type_init = 0;
    static Ptr_gconf_client_get_default p_gconf_client_get_default = 0;
    static Ptr_gconf_client_get_string p_gconf_client_get_string = 0;
    static Ptr_g_object_unref p_g_object_unref = 0;
    static Ptr_g_free p_g_free = 0;
}

static int kdeVersion()
{
    static int version = qgetenv("KDE_SESSION_VERSION").toInt();
    return version;
}

static QString kdeHome()
{
    static QString kdeHomePath;
    if (kdeHomePath.isEmpty()) {
        kdeHomePath = QFile::decodeName(qgetenv("KDEHOME"));
        if (kdeHomePath.isEmpty()) {
            int kdeSessionVersion = kdeVersion();
            QDir homeDir(QDir::homePath());
            QString kdeConfDir(QLatin1String("/.kde"));
            if (4 == kdeSessionVersion && homeDir.exists(QLatin1String(".kde4")))
                kdeConfDir = QLatin1String("/.kde4");
            kdeHomePath = QDir::homePath() + kdeConfDir;
        }
    }
    return kdeHomePath;
}

void QtIconLoaderImplementation::lookupIconTheme() const
{

#ifdef Q_WS_X11
    QString dataDirs = QFile::decodeName(getenv("XDG_DATA_DIRS"));
    if (dataDirs.isEmpty())
        dataDirs = QLatin1String("/usr/local/share/:/usr/share/");

    dataDirs.prepend(QDir::homePath() + QLatin1String("/:"));
    iconDirs = dataDirs.split(QLatin1Char(':'));

    // If we are running GNOME we resolve and use GConf. In all other
    // cases we currently use the KDE icon theme

    if (qgetenv("DESKTOP_SESSION") == "gnome" ||
        !qgetenv("GNOME_DESKTOP_SESSION_ID").isEmpty()) {

        if (themeName.isEmpty()) {
            // Resolve glib and gconf

            p_g_type_init =              (Ptr_g_type_init)QLibrary::resolve(QLatin1String("gobject-2.0"), 0, "g_type_init");
            p_gconf_client_get_default = (Ptr_gconf_client_get_default)QLibrary::resolve(QLatin1String("gconf-2"), 4, "gconf_client_get_default");
            p_gconf_client_get_string =  (Ptr_gconf_client_get_string)QLibrary::resolve(QLatin1String("gconf-2"), 4, "gconf_client_get_string");
            p_g_object_unref =           (Ptr_g_object_unref)QLibrary::resolve(QLatin1String("gobject-2.0"), 0, "g_object_unref");
            p_g_free =                   (Ptr_g_free)QLibrary::resolve(QLatin1String("glib-2.0"), 0, "g_free");

            if (p_g_type_init && p_gconf_client_get_default &&
                p_gconf_client_get_string && p_g_object_unref &&
                p_g_free) {

                p_g_type_init();
                GConfClient* client = p_gconf_client_get_default();

                // try meego first, since our 'default' target is meego
                char *str = p_gconf_client_get_string(client, "/meegotouch/theme/name", 0);
                if (str) {
                    themeName = QString::fromUtf8(str);
                        qDebug() << Q_FUNC_INFO << "Picked theme name from MeeGo key: " << themeName;
                } else {
                    // default gnome case
                    str = p_gconf_client_get_string(client, "/desktop/gnome/interface/icon_theme", 0);
                    if (str) {
                        themeName = QString::fromUtf8(str);
                        qDebug() << Q_FUNC_INFO << "Picked theme name from gnome key: " << themeName;
                    } else {
                        themeName = QString();
                    }
                }

                p_g_free(str);
                p_g_object_unref(client);
            }

            if (themeName.isEmpty()) {
                qDebug() << Q_FUNC_INFO << "Defaulted to 'gnome'";
                themeName = QLatin1String("gnome");
            }
        }

        if (!themeName.isEmpty())
            return;
    }

    // KDE (and others)
    if (dataDirs.isEmpty())
        dataDirs = QLatin1String("/usr/local/share/:/usr/share/");

    dataDirs += QLatin1Char(':') + kdeHome() + QLatin1String("/share");
    dataDirs.prepend(QDir::homePath() + QLatin1String("/:"));
    QStringList kdeDirs = QFile::decodeName(getenv("KDEDIRS")).split(QLatin1Char(':'));
    Q_FOREACH (const QString dirName, kdeDirs)
        dataDirs.append(QLatin1Char(':') + dirName + QLatin1String("/share"));
    iconDirs = dataDirs.split(QLatin1Char(':'));

    QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde"));
    QDir dir(fileInfo.canonicalFilePath());
    QString kdeDefault = kdeVersion() >= 4 ? QString::fromLatin1("oxygen") : QString::fromLatin1("crystalsvg");
    QString defaultTheme = fileInfo.exists() ? dir.dirName() : kdeDefault;
    QSettings settings(kdeHome() + QLatin1String("/share/config/kdeglobals"), QSettings::IniFormat);
    settings.beginGroup(QLatin1String("Icons"));
    themeName = settings.value(QLatin1String("Theme"), defaultTheme).toString();
#endif
    qDebug() << Q_FUNC_INFO << "Decided an icon theme of " << themeName;
}

QIconTheme QtIconLoaderImplementation::parseIndexFile(const QString &themeName) const
{
    QIconTheme theme;
    QFile themeIndex;
    QStringList parents;
    QHash <int, QString> dirList;

    for ( int i = 0 ; i < iconDirs.size() && !themeIndex.exists() ; ++i) {
        const QString &contentDir = QLatin1String(iconDirs[i].startsWith(QDir::homePath()) ? "/.icons/" : "/icons/");
        themeIndex.setFileName(iconDirs[i] + contentDir + themeName + QLatin1String("/index.theme"));
    }

    if (themeIndex.exists()) {
        QSettings indexReader(themeIndex.fileName(), QSettings::IniFormat);
        Q_FOREACH (const QString &key, indexReader.allKeys()) {
            if (key.endsWith("/Size")) {
                if (int size = indexReader.value(key).toInt())
                    dirList.insertMulti(size, key.left(key.size() - 5));
            }
        }

        // Parent themes provide fallbacks for missing icons
        parents = indexReader.value(QLatin1String("Icon Theme/Inherits")).toStringList();
    }

    if (kdeVersion() >= 3) {
        QFileInfo fileInfo(QLatin1String("/usr/share/icons/default.kde"));
        QDir dir(fileInfo.canonicalFilePath());
        QString defaultKDETheme = dir.exists() ? dir.dirName() : kdeVersion() == 3 ?
                                  QString::fromLatin1("crystalsvg") : QString::fromLatin1("oxygen");
        if (!parents.contains(defaultKDETheme) && themeName != defaultKDETheme)
            parents.append(defaultKDETheme);
    } else if (parents.isEmpty() && themeName != QLatin1String("hicolor")) {
        parents.append(QLatin1String("hicolor"));
    }

    theme = QIconTheme(dirList, parents);
    return theme;
}

QString QtIconLoaderImplementation::findIconHelper(int size, const QString &themeName,
                                                   const QString &iconName, QStringList &visited) const
{
    if (!themeName.isEmpty()) {
        visited << themeName;
        QIconTheme theme = themeList.value(themeName);

        if (!theme.isValid()) {
            theme = parseIndexFile(themeName);
            themeList.insert(themeName, theme);
        }

        if (!theme.isValid())
            return QString();

        QList <QString> subDirs = theme.dirList().values(size);
        QPixmap pixmap;

        for ( int i = 0 ; i < iconDirs.size() ; ++i) {
            for ( int j = 0 ; j < subDirs.size() ; ++j) {
                QString contentDir = (iconDirs[i].startsWith(QDir::homePath())) ?
                                     QLatin1String("/.icons/") : QLatin1String("/icons/");
                QString fileName = iconDirs[i] + contentDir + themeName + QLatin1Char('/') + subDirs[j] + QLatin1Char('/') + iconName;
                QFile file(fileName);
                pixmap = QPixmap(fileName);
                if (!pixmap.isNull())
                    return fileName;
            }
        }

        if (pixmap.isNull()) {
            QStringList parents = theme.parents();
            QString retval;
            //search recursively through inherited themes
            for (int i = 0 ; retval.isNull() && i < parents.size() ; ++i) {
                QString parentTheme = parents[i].trimmed();
                if (!visited.contains(parentTheme)) //guard against endless recursion
                    retval = findIconHelper(size, parentTheme, iconName, visited);
            }

            return retval;
        }
    }
    return QString();
}

QString QtIconLoaderImplementation::findIcon(int size, const QString &name) const
{
    if (!themeName.isEmpty()) {
        QStringList visited;
        return findIconHelper(size, themeName, name, visited);
    }
    return QString("???");
}
#endif //Q_WS_X11
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <cstring>
#include <vector>
#include <boost/algorithm/string/trim.hpp>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdlib>
#include <errno.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <set>
#include <iomanip>
#include <queue>
#include <stack>

using namespace std;
using namespace boost;

//next three bools used for ease of access to flags
bool hasa = false;	//holds flag for a
bool hasl = false;	//holds flag for l
bool hasR = false;	//hold flag for R

bool compareNoCase(const string& s1, const string& s2)
{		//takes care of capital letter comparisons
	return strcasecmp( s1.c_str(), s2.c_str() ) <= 0;
}

void make_strings(int size, char** parse, vector<string> &give)
{	//converts char** argv into vector of strings for easier use
	for(int i = 1; i < size; ++i)
	{
		give.push_back(string(parse[i]));
	}
}

void identify(vector<string> &commands, bool &cond)
{
	vector<string> replace;
	for(unsigned int i = 0; i < commands.size(); ++i)
	{
		if(commands.at(i).at(0) == '-')
		{
			if(commands.at(i).size() > 1)
			{
				for(unsigned int j = 1; j < commands.at(i).size(); ++j)
				{
					if((commands.at(i).at(j) == 'a') && !hasa)
					{
						hasa = true;
					}
					else if((commands.at(i).at(j) == 'l') && !hasl)
					{
						hasl = true;
					}
					else if((commands.at(i).at(j) == 'R') && !hasR)
					{
						hasR = true;
					}
					else if((commands.at(i).at(j) != 'R') && (commands.at(i).at(j) != 'a') && (commands.at(i).at(j) != 'l'))
					{
						cond = false;
					}
				}
			}
			else
			{
				cond = false;
			}
		}	//this function identifies where the directories are in the command line
		else
		{
			replace.push_back(commands.at(i));
		}	//determines what the flags are, and checks if they are all valid
	}
	commands = replace;
}

void getfiles(vector<string> &currfiles, char *temp)
//this function gets all the files and directories
{				//from whatever directory it is pointed to, and stores them in a vector of strings
	DIR *currdir;
	struct dirent *files;
	errno = 0;
	if(NULL == (currdir = opendir(temp)))
	{
		perror("There was an error with opendir() ");
		exit(1);
	}
	while(NULL != (files = readdir(currdir)))
	{
		if(hasa)
		{
			currfiles.push_back(string(files->d_name));
		}
		else
		{
			if(string(files->d_name).at(0) != '.')
			{
				currfiles.push_back(string(files->d_name));
			}
		}
	}
	if(errno != 0)
	{
		perror("There was an error with readdir() ");
		exit(1);
	}
	if(-1 == closedir(currdir))
	{
		perror("There was an error with closedir() ");
		exit(1);
	}
	sort(currfiles.begin(), currfiles.end(), compareNoCase);
}

void outputnorm(vector<string> &display)
{	//outputs the files/directories
	for(unsigned int i = 0; i < display.size(); ++i)
	{
		cout << display.at(i) << "  ";
		if(i == display.size() - 1)
		{
			cout << endl;
		}
	}
}

void getpath(const vector<string> &take, vector<string> &give, string &org, string &absname)
{
	string temp;
	bool fromhome = true;
	if(org.size() < 5)
	{
		fromhome = false;
	}
	else
	{
		for(unsigned int k = 0; k < 5; ++k)
		{
			if(org.at(k) != absname.at(k))
			{
				fromhome = false;
			}
		}
	}
	if(!fromhome)
	{
		temp = absname;
		for(unsigned int i = 0; i < take.size(); ++i)
		{
			absname.append(org);
			absname.append("/");
			absname.append(take.at(i));
			give.push_back(absname);
			absname = temp;
		}
	}
	else
	{
		temp = org;
		for(unsigned int i = 0; i < take.size(); ++i)
		{
			org.append("/");
			org.append(take.at(i));
			give.push_back(org);
			org = temp;
		}
	}
}

void getabsolName(string &name)
{
	char *ptr = new char[1024];
	if(NULL == (getcwd(ptr, 1024)))
	{
		perror("There was an error with getcwd() ");
		exit(1);
	}
	strcat(ptr, "/");
	name = string(ptr);
	delete []ptr;
}

void outputl(vector<string> &files, string &pname, string &absname)
{
	struct passwd *userid;
	struct group *groupid;
	struct stat status;
	vector<string> path;
	getpath(files, path, pname, absname);
	int total = 0;
	for(unsigned int i = 0; i < path.size(); ++i)
	{
		if(-1 == (stat(path.at(i).c_str(), &status)))
		{
			perror("There was an error with stat() ");
			exit(1);
		}
		else
		{
			total += status.st_blocks;
		}
	}
	cout << "Total: " << total/2 << endl;
	for(unsigned int i = 0; i < path.size(); ++i)
	{
		if(-1 == (stat(path.at(i).c_str(), &status)))
		{
			perror("There was an error with stat() ");
			exit(1);
		}
		else
		{
			if(S_IFDIR & status.st_mode)
			{
				cout << 'd';
			}
			else if(S_ISLNK(status.st_mode))
			{
				cout << 'l';
			}
			else
			{
				cout << '-';
			}
			cout << ((S_IRUSR & status.st_mode) ? 'r' : '-');
			cout << ((S_IWUSR & status.st_mode) ? 'w' : '-');
			cout << ((S_IXUSR & status.st_mode) ? 'x' : '-');
			cout << ((S_IRGRP & status.st_mode) ? 'r' : '-');
			cout << ((S_IWGRP & status.st_mode) ? 'w' : '-');
			cout << ((S_IXGRP & status.st_mode) ? 'x' : '-');
			cout << ((S_IROTH & status.st_mode) ? 'r' : '-');
			cout << ((S_IWOTH & status.st_mode) ? 'w' : '-');
			cout << ((S_IXOTH & status.st_mode) ? 'x' : '-');
			cout <<	' ' << status.st_nlink << ' ';
			if(NULL == (userid = getpwuid(status.st_uid)))
			{
				perror("There was an error with getpwuid() ");
				exit(1);
			}
			else
			{
				cout << userid->pw_name << ' ';
			}
			if(NULL == (groupid = getgrgid(status.st_gid)))
			{
				perror("There was an error with getgrdid() ");
				exit(1);
			}
			else
			{
				cout << groupid->gr_name << ' ';
			}
			cout << setw(7) << right << status.st_size << ' ';
			struct tm *tm;
			char timebuf[15];
			if(NULL == (tm = localtime(&(status.st_mtime))))
			{
				perror("There was an error with localtime() ");
				exit(1);
			}
			else
			{
				strftime(timebuf, 15, "%b %d %H:%M", tm);
				cout << timebuf << ' ';
			}
			cout << files.at(i);
		}
		cout << endl;
	}
}

void doR(vector<string> files, string parent, string absname)
{
	struct stat status;
	vector<string> filesnow;
	for(unsigned int i = 0; i < files.size(); i++)
	{
		if((files.at(i) != "." && files.at(i) !="..") && (hasa || (files.at(i).at(0) == '.' && files.at(i).at(1) =='/') || files.at(i).at(0) !='.'))
		{
			string pathname = parent + '/' + files.at(i);
			if(-1 == stat(pathname.c_str(), &status))
			{
				perror("There was an error with stat() ");
				exit(1);
			}
			if(S_IFDIR & status.st_mode)
			{
				cout << pathname << ":" << endl;
				getfiles(filesnow, const_cast<char*>(pathname.c_str()));
				if(hasl)
				{
					outputl(filesnow, pathname, absname);
					cout << endl;
				}
				else
				{
					outputnorm(filesnow);
					cout << endl;
				}
				doR(filesnow, pathname, absname);
			}
		}
		filesnow.clear();
	}
}

int main(int argc, char **argv)
{
	string absname;
	getabsolName(absname);
	vector<string> commands;
	vector<string> dirfiles;
	bool okay = true;
	make_strings(argc, argv, commands);		//first change all inputs into strings
	identify(commands, okay);		//organize and get all the info
	if(okay)	//if no errors in flag, proceed to output
	{
		if(commands.size() ==  0)	//if directories were not specified, come here
		{
			commands.push_back(".");
		}
		for(unsigned int i = 0; i < commands.size(); ++i)
		{
			getfiles(dirfiles, const_cast<char*>(commands.at(i).c_str()));
			if(commands.size() > 1)
			{
				cout << commands.at(i) << ": " << endl;
			}
			if(!hasl && !hasR)	//if no l or R flag, simple case, do this
			{
				outputnorm(dirfiles);
			}
			else if(hasl && !hasR)	//has the l flag but not R
			{
				outputl(dirfiles, commands.at(i), absname);
			}
			else if(hasR)	//has the R flag
			{
				if(hasl)
				{
					if(commands.size() <= 1)
					{
						cout << commands.at(i) << ":" << endl;
					}
					outputl(dirfiles, commands.at(i), absname);
				}
				else
				{
					if(commands.size() <= 1)
					{
						cout << commands.at(i) << ":" << endl;
					}
					outputnorm(dirfiles);
					cout << endl;
				}
				doR(dirfiles, commands.at(i), absname);
			}
			if(commands.size()-1 > i)
			{
				cout << endl;
			}
			dirfiles.clear();
		}
	}
	else
	{
		cout << "Error: flag not recognized or valid. " << endl;
	}
	return 0;
}
<commit_msg>refined outputting<commit_after>#include <iostream>
#include <string>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <string.h>
#include <cstring>
#include <vector>
#include <boost/algorithm/string/trim.hpp>
#include <sys/stat.h>
#include <fcntl.h>
#include <cstdlib>
#include <errno.h>
#include <dirent.h>
#include <pwd.h>
#include <grp.h>
#include <time.h>
#include <set>
#include <iomanip>
#include <queue>
#include <stack>

using namespace std;
using namespace boost;

//next three bools used for ease of access to flags
bool hasa = false;	//holds flag for a
bool hasl = false;	//holds flag for l
bool hasR = false;	//hold flag for R

bool compareNoCase(const string& s1, const string& s2)
{		//takes care of capital letter comparisons
	return strcasecmp( s1.c_str(), s2.c_str() ) <= 0;
}

void make_strings(int size, char** parse, vector<string> &give)
{	//converts char** argv into vector of strings for easier use
	for(int i = 1; i < size; ++i)
	{
		give.push_back(string(parse[i]));
	}
}

void identify(vector<string> &commands, bool &cond)
{
	vector<string> replace;
	for(unsigned int i = 0; i < commands.size(); ++i)
	{
		if(commands.at(i).at(0) == '-')
		{
			if(commands.at(i).size() > 1)
			{
				for(unsigned int j = 1; j < commands.at(i).size(); ++j)
				{
					if((commands.at(i).at(j) == 'a') && !hasa)
					{
						hasa = true;
					}
					else if((commands.at(i).at(j) == 'l') && !hasl)
					{
						hasl = true;
					}
					else if((commands.at(i).at(j) == 'R') && !hasR)
					{
						hasR = true;
					}
					else if((commands.at(i).at(j) != 'R') && (commands.at(i).at(j) != 'a') && (commands.at(i).at(j) != 'l'))
					{
						cond = false;
					}
				}
			}
			else
			{
				cond = false;
			}
		}	//this function identifies where the directories are in the command line
		else
		{
			replace.push_back(commands.at(i));
		}	//determines what the flags are, and checks if they are all valid
	}
	commands = replace;
}

void getfiles(vector<string> &currfiles, char *temp)
//this function gets all the files and directories
{				//from whatever directory it is pointed to, and stores them in a vector of strings
	DIR *currdir;
	struct dirent *files;
	errno = 0;
	if(NULL == (currdir = opendir(temp)))
	{
		perror("There was an error with opendir() ");
		exit(1);
	}
	while(NULL != (files = readdir(currdir)))
	{
		if(hasa)
		{
			currfiles.push_back(string(files->d_name));
		}
		else
		{
			if(string(files->d_name).at(0) != '.')
			{
				currfiles.push_back(string(files->d_name));
			}
		}
	}
	if(errno != 0)
	{
		perror("There was an error with readdir() ");
		exit(1);
	}
	if(-1 == closedir(currdir))
	{
		perror("There was an error with closedir() ");
		exit(1);
	}
	sort(currfiles.begin(), currfiles.end(), compareNoCase);
}

void outputnorm(vector<string> &display)
{	//outputs the files/directories
	unsigned int width = 0;
	for(unsigned int i = 0; i < display.size(); ++i)
	{
		if(display.at(i).size() > width)
		{
			width = display.at(i).size();
		}
	}
	unsigned int total = 0;
	for(unsigned int i = 0; i < display.size(); ++i)
	{
		total += width;
		if(total <= 80)
		{
			cout.width(width);
			cout << left <<  display.at(i) << "   ";
		}
		else
		{
			cout << endl;
			cout.width(width);
			cout << left << display.at(i) << "   ";
			total = 0;
		}
	}
	cout << endl;
}

void getpath(const vector<string> &take, vector<string> &give, string &org, string &absname)
{
	string temp;
	bool fromhome = true;
	if(org.size() < 5)
	{
		fromhome = false;
	}
	else
	{
		for(unsigned int k = 0; k < 5; ++k)
		{
			if(org.at(k) != absname.at(k))
			{
				fromhome = false;
			}
		}
	}
	if(!fromhome)
	{
		temp = absname;
		for(unsigned int i = 0; i < take.size(); ++i)
		{
			absname.append(org);
			absname.append("/");
			absname.append(take.at(i));
			give.push_back(absname);
			absname = temp;
		}
	}
	else
	{
		temp = org;
		for(unsigned int i = 0; i < take.size(); ++i)
		{
			org.append("/");
			org.append(take.at(i));
			give.push_back(org);
			org = temp;
		}
	}
}

void getabsolName(string &name)
{
	char *ptr = new char[1024];
	if(NULL == (getcwd(ptr, 1024)))
	{
		perror("There was an error with getcwd() ");
		exit(1);
	}
	strcat(ptr, "/");
	name = string(ptr);
	delete []ptr;
}

void outputl(vector<string> &files, string &pname, string &absname)
{
	struct passwd *userid;
	struct group *groupid;
	struct stat status;
	vector<string> path;
	getpath(files, path, pname, absname);
	int total = 0;
	for(unsigned int i = 0; i < path.size(); ++i)
	{
		if(-1 == (stat(path.at(i).c_str(), &status)))
		{
			perror("There was an error with stat() ");
			exit(1);
		}
		else
		{
			total += status.st_blocks;
		}
	}
	cout << "Total: " << total/2 << endl;
	for(unsigned int i = 0; i < path.size(); ++i)
	{
		if(-1 == (stat(path.at(i).c_str(), &status)))
		{
			perror("There was an error with stat() ");
			exit(1);
		}
		else
		{
			if(S_IFDIR & status.st_mode)
			{
				cout << 'd';
			}
			else if(S_ISLNK(status.st_mode))
			{
				cout << 'l';
			}
			else
			{
				cout << '-';
			}
			cout << ((S_IRUSR & status.st_mode) ? 'r' : '-');
			cout << ((S_IWUSR & status.st_mode) ? 'w' : '-');
			cout << ((S_IXUSR & status.st_mode) ? 'x' : '-');
			cout << ((S_IRGRP & status.st_mode) ? 'r' : '-');
			cout << ((S_IWGRP & status.st_mode) ? 'w' : '-');
			cout << ((S_IXGRP & status.st_mode) ? 'x' : '-');
			cout << ((S_IROTH & status.st_mode) ? 'r' : '-');
			cout << ((S_IWOTH & status.st_mode) ? 'w' : '-');
			cout << ((S_IXOTH & status.st_mode) ? 'x' : '-');
			cout <<	' ' << status.st_nlink << ' ';
			if(NULL == (userid = getpwuid(status.st_uid)))
			{
				perror("There was an error with getpwuid() ");
				exit(1);
			}
			else
			{
				cout << userid->pw_name << ' ';
			}
			if(NULL == (groupid = getgrgid(status.st_gid)))
			{
				perror("There was an error with getgrdid() ");
				exit(1);
			}
			else
			{
				cout << groupid->gr_name << ' ';
			}
			cout << setw(7) << right << status.st_size << ' ';
			struct tm *tm;
			char timebuf[15];
			if(NULL == (tm = localtime(&(status.st_mtime))))
			{
				perror("There was an error with localtime() ");
				exit(1);
			}
			else
			{
				strftime(timebuf, 15, "%b %d %H:%M", tm);
				cout << timebuf << ' ';
			}
			cout << files.at(i);
		}
		cout << endl;
	}
}

void doR(vector<string> files, string parent, string absname)
{
	struct stat status;
	vector<string> filesnow;
	for(unsigned int i = 0; i < files.size(); i++)
	{
		if((files.at(i) != "." && files.at(i) !="..") && (hasa || (files.at(i).at(0) == '.' && files.at(i).at(1) =='/') || files.at(i).at(0) !='.'))
		{
			string pathname = parent + '/' + files.at(i);
			if(-1 == stat(pathname.c_str(), &status))
			{
				perror("There was an error with stat() ");
				exit(1);
			}
			if(S_IFDIR & status.st_mode)
			{
				cout << pathname << ":" << endl;
				getfiles(filesnow, const_cast<char*>(pathname.c_str()));
				if(hasl)
				{
					outputl(filesnow, pathname, absname);
					cout << endl;
				}
				else
				{
					outputnorm(filesnow);
					cout << endl;
				}
				doR(filesnow, pathname, absname);
			}
		}
		filesnow.clear();
	}
}

int main(int argc, char **argv)
{
	string absname;
	getabsolName(absname);
	vector<string> commands;
	vector<string> dirfiles;
	bool okay = true;
	make_strings(argc, argv, commands);		//first change all inputs into strings
	identify(commands, okay);		//organize and get all the info
	if(okay)	//if no errors in flag, proceed to output
	{
		if(commands.size() ==  0)	//if directories were not specified, come here
		{
			commands.push_back(".");
		}
		for(unsigned int i = 0; i < commands.size(); ++i)
		{
			getfiles(dirfiles, const_cast<char*>(commands.at(i).c_str()));
			if(commands.size() > 1)
			{
				cout << commands.at(i) << ": " << endl;
			}
			if(!hasl && !hasR)	//if no l or R flag, simple case, do this
			{
				outputnorm(dirfiles);
			}
			else if(hasl && !hasR)	//has the l flag but not R
			{
				outputl(dirfiles, commands.at(i), absname);
			}
			else if(hasR)	//has the R flag
			{
				if(hasl)
				{
					if(commands.size() <= 1)
					{
						cout << commands.at(i) << ":" << endl;
					}
					outputl(dirfiles, commands.at(i), absname);
				}
				else
				{
					if(commands.size() <= 1)
					{
						cout << commands.at(i) << ":" << endl;
					}
					outputnorm(dirfiles);
					cout << endl;
				}
				doR(dirfiles, commands.at(i), absname);
			}
			if(i < (commands.size() - 1))
			{
				cout << endl;
			}
			dirfiles.clear();
		}
	}
	else
	{
		cout << "Error: flag not recognized or valid. " << endl;
	}
	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <vector>
#include <sstream>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
using namespace std;

bool isDirectory(char* directoryName) {

	struct stat directoryInCurrent;

	if (-1 == (stat(directoryName, &directoryInCurrent))) {

		perror("stat failed");
		return false;
	}

	if (directoryInCurrent.st_mode & S_IFDIR) {
		return true;
	}
	else {
		return false;
	}
}

int ls(char* directoryName) {

		char const *dirName = ".";
		DIR *dirp;
		if (!(dirp = opendir(dirName))) {
			cerr << "Error(" << errno << ") opening " << dirName << endl;
		}

		dirent *direntp;
		while ((direntp = readdir(dirp))) {
			if (direntp->d_name[0] != '.') {

				//cout << direntp->d_name << endl; // use stat here to find attributes of a file
				printf(direntp->d_name, 8);
				cout << " ";
			}
		}
		cout << endl;
		closedir(dirp);
		return 0;
}

int lsWithFlags(char* directoryName, vector<string> flags) {

	bool isA = false;
	bool isL = false;
	bool isR = false;
	for (unsigned i = 0; i < flags.size(); ++i) {
		for (unsigned k = 0; k < flags.at(i).size(); ++k) {
			if (flags.at(i).at(k) == 'a')
				isA = true;
			else if (flags.at(i).at(k) == 'l')
				isL = true;
			else if (flags.at(i).at(k) == 'R')
				isR = true;
		}

	}
	char const *dirName = directoryName;
	DIR *dirp;
	if (!(dirp = opendir(dirName))) {
		cerr << "Error(" << errno << ") opening " << dirName << endl;
		return errno;
	}

	dirent *direntp;
	if (isA) {
		while ((direntp = readdir(dirp))) {

			//cout << direntp->d_name << endl; // use stat here to find attributes of a file
			printf(direntp->d_name, 8);
			cout << " ";

		}
	}
	cout << endl;
	closedir(dirp);
	return 0;
}

int main(int argc, char* argv[]) {

	if (argc == 1) {

		if (errno == ls(".")) {

			return errno;
		}
	}

	else {

		vector<string> directories;
		vector<string> flags;
		for (int i = 1; i < argc; ++i) {

			if (argv[i][0] == '-') {
				flags.push_back(argv[i]);
			}
			else {

				if (isDirectory(argv[i])) {

					directories.push_back(argv[i]);
				}
			}
		}
		if (directories.size() == 0) {

			if (errno == lsWithFlags(".", flags)) {

				return errno;
			}
		}
	}

}

<commit_msg>changed conditions for boolean variables in lswithflags function<commit_after>#include <iostream>
#include <unistd.h>
#include <sys/stat.h>
#include <stdio.h>
#include <vector>
#include <sstream>
#include <dirent.h>
#include <errno.h>
#include <sys/types.h>
using namespace std;

bool isDirectory(char* directoryName) {

	struct stat directoryInCurrent;

	if (-1 == (stat(directoryName, &directoryInCurrent))) {

		perror("stat failed");
		return false;
	}

	if (directoryInCurrent.st_mode & S_IFDIR) {
		return true;
	}
	else {
		return false;
	}
}

int ls(char* directoryName) {

		char const *dirName = ".";
		DIR *dirp;
		if (!(dirp = opendir(dirName))) {
			cerr << "Error(" << errno << ") opening " << dirName << endl;
		}

		dirent *direntp;
		while ((direntp = readdir(dirp))) {
			if (direntp->d_name[0] != '.') {

				//cout << direntp->d_name << endl; // use stat here to find attributes of a file
				printf(direntp->d_name, 8);
				cout << " ";
			}
		}
		cout << endl;
		closedir(dirp);
		return 0;
}

int lsWithFlags(char* directoryName, vector<string> flags) {

	bool isA = false;
	bool isL = false;
	bool isR = false;
	for (unsigned i = 0; i < flags.size(); ++i) {
		for (unsigned k = 0; k < flags.at(i).size(); ++k) {
			if (flags.at(i).at(k) == 'a')
				isA = true;
			else if (flags.at(i).at(k) == 'l')
				isL = true;
			else if (flags.at(i).at(k) == 'R')
				isR = true;
		}

	}
	char const *dirName = directoryName;
	DIR *dirp;
	if (!(dirp = opendir(dirName))) {
		cerr << "Error(" << errno << ") opening " << dirName << endl;
		return errno;
	}

	dirent *direntp;
	if (isA) {
		while ((direntp = readdir(dirp))) {

			//cout << direntp->d_name << endl; // use stat here to find attributes of a file
			printf(direntp->d_name, 8);
			cout << " ";

		}
	}
	cout << endl;
	closedir(dirp);
	return 0;
}

int main(int argc, char* argv[]) {

	if (argc == 1) {

		if (errno == ls(".")) {

			return errno;
		}
	}

	else {

		vector<string> directories;
		vector<string> flags;
		vector<int> directoryIndex;
		bool directoryInArgv = false;
		for (int i = 1; i < argc; ++i) {

			if (isDirectory(argv[i]) {
				directoryInArgv = true;
				break;
			}
			else {

				if (argv[i]
			}
		}
		if (directories.size() == 0) {

			if (errno == lsWithFlags(".", flags)) {

				return errno;
			}
		}
		else {

			for (int i = 0; i < argc; ++i) {

				if (isDirectory(argv[i]) {
					directories.push_back(argv[i]);
					directoryIndex.push_back(i);
				}
			}

			for (int i = 0; i < directories.size(); ++i) {
				flags.clear();
				for (int k = directoryIndex.at(i); (i + 1) < directoryIndex.size() &&
							k != directoryIndex.at(i + 1); ++k) {
					if (argv[k][0] == '-') {

						flags.push_back(argv[k]);
					}
				}

				if (errno == lsWithFlags(directories.at(i), flags) {

					return errno;
				}
			}
		}
	}

}

<|endoftext|>


<commit_before>#include <fcntl.h>

#include <netinet/in.h>
#include <sys/socket.h>

#include "server.h"
#include "net/length.h"

#include "xapian.h"

void print_string(const std::string &string) {
	const char *p = string.c_str();
	const char *p_end = p + string.size();
	printf("'");
	while (p != p_end) {
		if (*p >= ' ' && *p <= '~') {
			printf("%c", *p++);
		} else {
			printf("\\x%02x", *p++ & 0xff);
		}
	}
	printf("'\n");
}

class XapianWorker : public Task {
private:
	XapiandClient *client;

public:
	XapianWorker(XapiandClient *client_) : Task(), client(client_) {}

	~XapianWorker() {}

	virtual void run() {
		client->run_one();
	}
};

//
//   Buffer class - allow for output buffering such that it can be written out
//                                 into async pieces
//
struct Buffer {
	char type;
	char *data;
	ssize_t len;
	ssize_t pos;

	Buffer(char type_, const char *bytes, ssize_t nbytes) {
		pos = 0;
		len = nbytes;
		type = type_;
		data = new char[nbytes];
		memcpy(data, bytes, nbytes);
	}

	virtual ~Buffer() {
		delete [] data;
	}

	char *dpos() {
		return data + pos;
	}

	ssize_t nbytes() {
		return len - pos;
	}
};

message_type
custom_get_message(void * obj, double timeout, std::string & result,
			message_type required_type)
{
	XapiandClient * client = static_cast<XapiandClient *>(obj);
	return client->get_message(timeout, result);
}

void
custom_send_message(void * obj, reply_type type, const std::string &message)
{
	XapiandClient * client = static_cast<XapiandClient *>(obj);
	client->send_message(type, message);
}

Xapian::Database * custom_get_database(void * obj, const std::vector<std::string> &dbpaths)
{
	if (dbpaths.empty()) return NULL;
	Xapian::Database *db = new Xapian::Database(dbpaths[0], Xapian::DB_CREATE_OR_OPEN);
	return db;
}

Xapian::WritableDatabase * custom_get_writable_database(void * obj, const std::vector<std::string> &dbpaths)
{
	if (dbpaths.empty()) return NULL;
	Xapian::WritableDatabase *db = new Xapian::WritableDatabase(dbpaths[0], Xapian::DB_CREATE_OR_OPEN);
	return db;
}

void XapiandClient::callback(ev::io &watcher, int revents)
{
	if (EV_ERROR & revents) {
		perror("got invalid event");
		return;
	}

	if (revents & EV_READ)
		read_cb(watcher);

	if (revents & EV_WRITE)
		write_cb(watcher);

	pthread_mutex_lock(&qmtx);
	if (write_queue.empty()) {
		io.set(ev::READ);
	} else {
		io.set(ev::READ|ev::WRITE);
	}
	pthread_mutex_unlock(&qmtx);
}

void XapiandClient::async_cb(ev::async &watcher, int revents)
{
	pthread_mutex_lock(&qmtx);
	if (!write_queue.empty()) {
		io.set(ev::READ|ev::WRITE);
	}
	pthread_mutex_unlock(&qmtx);
}

void XapiandClient::write_cb(ev::io &watcher)
{
	pthread_mutex_lock(&qmtx);

	if (write_queue.empty()) {
		io.set(ev::READ);
	} else {
		Buffer* buffer = write_queue.front();

		// printf("sent:");
		// print_string(std::string(buffer->dpos(), buffer->nbytes()));

		ssize_t written = write(watcher.fd, buffer->dpos(), buffer->nbytes());
		if (written < 0) {
			perror("read error");
		} else {
			buffer->pos += written;
			if (buffer->nbytes() == 0) {
				write_queue.pop_front();
				delete buffer;
			}
		}
	}

	pthread_mutex_unlock(&qmtx);
}

void XapiandClient::read_cb(ev::io &watcher)
{
	char buf[1024];

	ssize_t received = recv(watcher.fd, buf, sizeof(buf), 0);

	if (received < 0) {
		perror("read error");
		return;
	}

	if (received == 0) {
		// Gack - we're deleting ourself inside of ourself!
		delete this;
	} else {
		buffer.append(buf, received);
		if (buffer.length() >= 2) {
			const char *o = buffer.data();
			const char *p = o;
			const char *p_end = p + buffer.size();

			message_type required_type = static_cast<message_type>(*p++);
			size_t len;
			try {
				len = decode_length(&p, p_end, true);
			} catch (const Xapian::NetworkError & e) {
				return;
			}
			std::string data = std::string(p, len);
			buffer.erase(0, p - o + len);

			// printf("received:");
			// print_string(data);

			Buffer *msg = new Buffer(required_type, data.c_str(), data.size());

			messages_queue.push(msg);

			if (required_type == '\x08') {
				thread_pool->addTask(new XapianWorker(this));
			}

		}
	}
}

void XapiandClient::signal_cb(ev::sig &signal, int revents)
{
	delete this;
}

message_type XapiandClient::get_message(double timeout, std::string & result)
{
	Buffer* msg;
	if (!messages_queue.pop(msg)) {
		throw Xapian::NetworkError("No message available");
	}

	std::string buf(&msg->type, 1);
	buf += encode_length(msg->nbytes());
	buf += std::string(msg->dpos(), msg->nbytes());
	printf("get_message:");
	print_string(buf);

	message_type required_type = static_cast<message_type>(msg->type);
	result.assign(msg->dpos(), msg->nbytes());

	delete msg;
	return required_type;
}

void XapiandClient::send_message(reply_type type, const std::string &message)
{
	char type_as_char = static_cast<char>(type);
	std::string buf(&type_as_char, 1);
	buf += encode_length(message.size());
	buf += message;

	printf("send_message:");
	print_string(buf);

	pthread_mutex_lock(&qmtx);
	write_queue.push_back(new Buffer(type, buf.c_str(), buf.size()));
	pthread_mutex_unlock(&qmtx);

	async.send();
}

XapiandClient::XapiandClient(int sock_, ThreadPool *thread_pool_)
	: sock(sock_),
	  thread_pool(thread_pool_),
	  server(NULL)
{
	pthread_mutex_init(&qmtx, 0);

	fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);

	printf("Got connection, %d client(s) connected.\n", ++total_clients);

	io.set<XapiandClient, &XapiandClient::callback>(this);
	io.start(sock, ev::READ);

	sig.set<XapiandClient, &XapiandClient::signal_cb>(this);
	sig.start(SIGINT);

	async.set<XapiandClient, &XapiandClient::async_cb>(this);
	async.start();

	dbpaths.push_back("test");
	server = new RemoteServer(
		this,
		dbpaths, true,
		custom_get_message,
		custom_send_message,
		custom_get_database,
		custom_get_writable_database
	);

	try {
		server->msg_update(std::string());
	} catch (const Xapian::NetworkError &e) {
		printf("ERROR: %s\n", e.get_msg().c_str());
	} catch (...) {
		printf("ERROR!\n");
	}
}

XapiandClient::~XapiandClient()
{
	shutdown(sock, SHUT_RDWR);

	// Stop and free watcher if client socket is closing
	io.stop();
	sig.stop();
	async.stop();

	close(sock);

	printf("Lost connection, %d client(s) connected.\n", --total_clients);

	pthread_mutex_destroy(&qmtx);

	delete server;
}

void XapiandClient::run_one()
{
	try {
		server->run_one();
	} catch (const Xapian::NetworkError &e) {
		printf("ERROR: %s\n", e.get_msg().c_str());
	} catch (...) {
		printf("ERROR!\n");
	}
}

void XapiandServer::io_accept(ev::io &watcher, int revents)
{
	if (EV_ERROR & revents) {
		perror("got invalid event");
		return;
	}

	struct sockaddr_in client_addr;
	socklen_t client_len = sizeof(client_addr);

	int client_sock = accept(watcher.fd, (struct sockaddr *)&client_addr, &client_len);

	if (client_sock < 0) {
		perror("accept error");
		return;
	}

	new XapiandClient(client_sock, this->thread_pool);
}

void XapiandServer::signal_cb(ev::sig &signal, int revents)
{
	signal.loop.break_loop();
}

XapiandServer::XapiandServer(int port, ThreadPool *thread_pool_)
	: thread_pool(thread_pool_)
{
	int optval = 1;
	struct sockaddr_in addr;

	sock = socket(PF_INET, SOCK_STREAM, 0);
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = INADDR_ANY;

	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
		perror("bind");
		close(sock);
		sock = 0;
	} else {
		printf("Listening on port %d\n", port);
		fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);

		listen(sock, 5);

		io.set<XapiandServer, &XapiandServer::io_accept>(this);
		io.start(sock, ev::READ);

		sig.set<&XapiandServer::signal_cb>();
		sig.start(SIGINT);
	}
}

XapiandServer::~XapiandServer()
{
	shutdown(sock, SHUT_RDWR);

	io.stop();
	sig.stop();

	close(sock);

	printf("Done with all work!\n");
}

int XapiandClient::total_clients = 0;
<commit_msg>Fixed indentation and queue issue<commit_after>#include <fcntl.h>

#include <netinet/in.h>
#include <sys/socket.h>

#include "server.h"
#include "net/length.h"

#include "xapian.h"

void print_string(const std::string &string) {
	const char *p = string.c_str();
	const char *p_end = p + string.size();
	printf("'");
	while (p != p_end) {
		if (*p >= ' ' && *p <= '~') {
			printf("%c", *p++);
		} else {
			printf("\\x%02x", *p++ & 0xff);
		}
	}
	printf("'\n");
}

class XapianWorker : public Task {
private:
	XapiandClient *client;

public:
	XapianWorker(XapiandClient *client_) : Task(), client(client_) {}

	~XapianWorker() {}

	virtual void run() {
		client->run_one();
	}
};

//
//   Buffer class - allow for output buffering such that it can be written out
//                                 into async pieces
//
struct Buffer {
	char type;
	char *data;
	ssize_t len;
	ssize_t pos;

	Buffer(char type_, const char *bytes, ssize_t nbytes) {
		pos = 0;
		len = nbytes;
		type = type_;
		data = new char[nbytes];
		memcpy(data, bytes, nbytes);
	}

	virtual ~Buffer() {
		delete [] data;
	}

	char *dpos() {
		return data + pos;
	}

	ssize_t nbytes() {
		return len - pos;
	}
};

message_type
custom_get_message(void * obj, double timeout, std::string & result,
			message_type required_type)
{
	XapiandClient * client = static_cast<XapiandClient *>(obj);
	return client->get_message(timeout, result);
}

void
custom_send_message(void * obj, reply_type type, const std::string &message)
{
	XapiandClient * client = static_cast<XapiandClient *>(obj);
	client->send_message(type, message);
}

Xapian::Database * custom_get_database(void * obj, const std::vector<std::string> &dbpaths)
{
	if (dbpaths.empty()) return NULL;
	Xapian::Database *db = new Xapian::Database(dbpaths[0], Xapian::DB_CREATE_OR_OPEN);
	return db;
}

Xapian::WritableDatabase * custom_get_writable_database(void * obj, const std::vector<std::string> &dbpaths)
{
	if (dbpaths.empty()) return NULL;
	Xapian::WritableDatabase *db = new Xapian::WritableDatabase(dbpaths[0], Xapian::DB_CREATE_OR_OPEN);
	return db;
}

void XapiandClient::callback(ev::io &watcher, int revents)
{
	if (EV_ERROR & revents) {
		perror("got invalid event");
		return;
	}

	if (revents & EV_READ)
		read_cb(watcher);

	if (revents & EV_WRITE)
		write_cb(watcher);

	pthread_mutex_lock(&qmtx);
	if (write_queue.empty()) {
		io.set(ev::READ);
	} else {
		io.set(ev::READ|ev::WRITE);
	}
	pthread_mutex_unlock(&qmtx);
}

void XapiandClient::async_cb(ev::async &watcher, int revents)
{
	pthread_mutex_lock(&qmtx);
	if (!write_queue.empty()) {
		io.set(ev::READ|ev::WRITE);
	}
	pthread_mutex_unlock(&qmtx);
}

void XapiandClient::write_cb(ev::io &watcher)
{
	pthread_mutex_lock(&qmtx);

	if (write_queue.empty()) {
		io.set(ev::READ);
	} else {
		Buffer* buffer = write_queue.front();

		// printf("sent:");
		// print_string(std::string(buffer->dpos(), buffer->nbytes()));

		ssize_t written = write(watcher.fd, buffer->dpos(), buffer->nbytes());
		if (written < 0) {
			perror("read error");
		} else {
			buffer->pos += written;
			if (buffer->nbytes() == 0) {
				write_queue.pop_front();
				delete buffer;
			}
		}
	}

	pthread_mutex_unlock(&qmtx);
}

void XapiandClient::read_cb(ev::io &watcher)
{
	char buf[1024];

	ssize_t received = recv(watcher.fd, buf, sizeof(buf), 0);

	if (received < 0) {
		perror("read error");
		return;
	}

	if (received == 0) {
		// Gack - we're deleting ourself inside of ourself!
		delete this;
	} else {
		buffer.append(buf, received);
		if (buffer.length() >= 2) {
			const char *o = buffer.data();
			const char *p = o;
			const char *p_end = p + buffer.size();

			message_type required_type = static_cast<message_type>(*p++);
			size_t len;
			try {
				len = decode_length(&p, p_end, true);
			} catch (const Xapian::NetworkError & e) {
				return;
			}
			std::string data = std::string(p, len);
			buffer.erase(0, p - o + len);

			// printf("received:");
			// print_string(data);

			Buffer *msg = new Buffer(required_type, data.c_str(), data.size());

			messages_queue.push(msg);

			if (required_type == MSG_QUERY) {
				thread_pool->addTask(new XapianWorker(this));
			}

		}
	}
}

void XapiandClient::signal_cb(ev::sig &signal, int revents)
{
	delete this;
}

message_type XapiandClient::get_message(double timeout, std::string & result)
{
	Buffer* msg;
	if (!messages_queue.pop(msg)) {
		throw Xapian::NetworkError("No message available");
	}

	std::string buf(&msg->type, 1);
	buf += encode_length(msg->nbytes());
	buf += std::string(msg->dpos(), msg->nbytes());
	printf("get_message:");
	print_string(buf);

	message_type required_type = static_cast<message_type>(msg->type);
	result.assign(msg->dpos(), msg->nbytes());

	delete msg;
	return required_type;
}

void XapiandClient::send_message(reply_type type, const std::string &message)
{
	char type_as_char = static_cast<char>(type);
	std::string buf(&type_as_char, 1);
	buf += encode_length(message.size());
	buf += message;

	printf("send_message:");
	print_string(buf);

	pthread_mutex_lock(&qmtx);
	write_queue.push_back(new Buffer(type, buf.c_str(), buf.size()));
	pthread_mutex_unlock(&qmtx);

	async.send();
}

void XapiandClient::run_one()
{
	try {
		server->run_one();
	} catch (const Xapian::NetworkError &e) {
		printf("ERROR: %s\n", e.get_msg().c_str());
	} catch (...) {
		printf("ERROR!\n");
	}
}

XapiandClient::XapiandClient(int sock_, ThreadPool *thread_pool_)
	: sock(sock_),
	  thread_pool(thread_pool_),
	  server(NULL)
{
	pthread_mutex_init(&qmtx, 0);

	fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);

	printf("Got connection, %d client(s) connected.\n", ++total_clients);

	io.set<XapiandClient, &XapiandClient::callback>(this);
	io.start(sock, ev::READ);

	sig.set<XapiandClient, &XapiandClient::signal_cb>(this);
	sig.start(SIGINT);

	async.set<XapiandClient, &XapiandClient::async_cb>(this);
	async.start();

	dbpaths.push_back("/Users/kronuz/Development/Dubalu/Xapian/xapian-core-1.3.2/bin/Xapiand/test");
	server = new RemoteServer(
		this,
		dbpaths, true,
		custom_get_message,
		custom_send_message,
		custom_get_database,
		custom_get_writable_database
	);

	try {
		server->msg_update(std::string());
	} catch (const Xapian::NetworkError &e) {
		printf("ERROR: %s\n", e.get_msg().c_str());
	} catch (...) {
		printf("ERROR!\n");
	}
}

XapiandClient::~XapiandClient()
{
	shutdown(sock, SHUT_RDWR);

	// Stop and free watcher if client socket is closing
	io.stop();
	sig.stop();
	async.stop();

	close(sock);

	printf("Lost connection, %d client(s) connected.\n", --total_clients);

	pthread_mutex_destroy(&qmtx);

	delete server;
}

void XapiandServer::io_accept(ev::io &watcher, int revents)
{
	if (EV_ERROR & revents) {
		perror("got invalid event");
		return;
	}

	struct sockaddr_in client_addr;
	socklen_t client_len = sizeof(client_addr);

	int client_sock = accept(watcher.fd, (struct sockaddr *)&client_addr, &client_len);

	if (client_sock < 0) {
		perror("accept error");
		return;
	}

	new XapiandClient(client_sock, this->thread_pool);
}

void XapiandServer::signal_cb(ev::sig &signal, int revents)
{
	signal.loop.break_loop();
}

XapiandServer::XapiandServer(int port, ThreadPool *thread_pool_)
	: thread_pool(thread_pool_)
{
	int optval = 1;
	struct sockaddr_in addr;

	sock = socket(PF_INET, SOCK_STREAM, 0);
	setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&optval, sizeof(optval));

	addr.sin_family = AF_INET;
	addr.sin_port = htons(port);
	addr.sin_addr.s_addr = INADDR_ANY;

	if (bind(sock, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
		perror("bind");
		close(sock);
		sock = 0;
	} else {
		printf("Listening on port %d\n", port);
		fcntl(sock, F_SETFL, fcntl(sock, F_GETFL, 0) | O_NONBLOCK);

		listen(sock, 5);

		io.set<XapiandServer, &XapiandServer::io_accept>(this);
		io.start(sock, ev::READ);

		sig.set<&XapiandServer::signal_cb>();
		sig.start(SIGINT);
	}
}

XapiandServer::~XapiandServer()
{
	shutdown(sock, SHUT_RDWR);

	io.stop();
	sig.stop();

	close(sock);

	printf("Done with all work!\n");
}

int XapiandClient::total_clients = 0;
<|endoftext|>