<commit_before>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    unixdomainsocketserver.cpp
 * @date    07.05.2015
 * @author  Alexandre Poirot <alexandre.poirot@legrand.fr>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "unixdomainsocketserver.h"
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <sys/types.h>
#include <jsonrpccpp/common/specificationparser.h>
#include <cstdio>
#include <unistd.h>
#include <string>

using namespace jsonrpc;
using namespace std;

#define BUFFER_SIZE 64
#define PATH_MAX 108
#ifndef DELIMITER_CHAR
#define DELIMITER_CHAR char(0x0A)
#endif //DELIMITER_CHAR

UnixDomainSocketServer::UnixDomainSocketServer(const string &socket_path) :
	AbstractServerConnector(),
	socket_path(socket_path.substr(0, PATH_MAX)),
	running(false)
{
}

bool UnixDomainSocketServer::StartListening()
{
	if(!this->running)
	{
		//Create and bind socket here.
		//Then launch the listenning loop.
		this->socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if(this->socket_fd < 0)
		{
			cerr << "socket() failed" << endl;
			return false;
		}

		unlink(this->socket_path.c_str());

		/* start with a clean address structure */
		memset(&(this->address), 0, sizeof(struct sockaddr_un));

		this->address.sun_family = AF_UNIX;
		snprintf(this->address.sun_path, PATH_MAX, this->socket_path.c_str());

		if(bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_un)) != 0)
		{
			cerr << "bind() failed" << endl;
			return false;
		}

		if(listen(this->socket_fd, 5) != 0)
		{
			cerr << "listen() failed" << endl;
			return false;
		}
		//Launch listening loop there
		int ret = pthread_create(&(this->listenning_thread), NULL, UnixDomainSocketServer::LaunchLoop, this);
		if(ret != 0) {
			pthread_detach(this->listenning_thread);
		}
		this->running = static_cast<bool>(ret==0);
	}
	return this->running;
}

bool UnixDomainSocketServer::StopListening()
{
	if(this->running)
	{
		close(this->socket_fd);
		unlink(this->socket_path.c_str());
		this->running = false;
	}
	return true;
}

bool UnixDomainSocketServer::SendResponse(const string& response, void* addInfo)
{
	bool result = false;
	int connection_fd = reinterpret_cast<intptr_t>(addInfo);

	string temp = response;
	if(temp.find(DELIMITER_CHAR) == string::npos) {
		temp.append(1, DELIMITER_CHAR);
	}
	if(DELIMITER_CHAR != '\n') {
		char eot = DELIMITER_CHAR;
		string toSend = temp.substr(0, toSend.find_last_of('\n'));
		toSend += eot;
		result = this->WriteToSocket(connection_fd, toSend);
	}
	else {
		result = this->WriteToSocket(connection_fd, temp);
	}
	close(connection_fd);
	return result;
}

void* UnixDomainSocketServer::LaunchLoop(void *p_data) {
	UnixDomainSocketServer *instance = reinterpret_cast<UnixDomainSocketServer*>(p_data);;
	instance->ListenLoop();
}

void UnixDomainSocketServer::ListenLoop() {
	int connection_fd;
	socklen_t address_length = sizeof(this->address);
	while((connection_fd = accept(this->socket_fd, (struct sockaddr *) &(this->address),  &address_length)) > -1)
	{
		pthread_t client_thread;
		struct GenerateResponseParameters *params = new struct GenerateResponseParameters();
		params->instance = this;
		params->connection_fd = connection_fd;
		int ret = pthread_create(&client_thread, NULL, UnixDomainSocketServer::GenerateResponse, params);
		if(ret != 0) {
			pthread_detach(client_thread);
			delete params;
			params = NULL;
		}
	}
}

void* UnixDomainSocketServer::GenerateResponse(void *p_data) {
	struct GenerateResponseParameters* params = reinterpret_cast<struct GenerateResponseParameters*>(p_data);
	UnixDomainSocketServer *instance = params->instance;
	int connection_fd = params->connection_fd;
	delete params;
	params = NULL;
	int nbytes;
	char buffer[BUFFER_SIZE];
	string request;
	do { //The client sends its json formatted request and a delimiter request.
		nbytes = read(connection_fd, buffer, BUFFER_SIZE);
		request.append(buffer,nbytes);
	} while(request.find(DELIMITER_CHAR) == string::npos);
	instance->OnRequest(request, reinterpret_cast<void*>(connection_fd));
}

bool UnixDomainSocketServer::WriteToSocket(int fd, const string& toWrite) {
	bool fullyWritten = false;
	bool errorOccured = false;
	string toSend = toWrite;
	do {
		ssize_t byteWritten = write(fd, toSend.c_str(), toSend.size());
		if(byteWritten < 0)
			errorOccured = true;
		else if(byteWritten < toSend.size()) {
			int len = toSend.size() - byteWritten;
			toSend = toSend.substr(byteWritten + sizeof(char), len);
		}
		else
			fullyWritten = true;
	} while(!fullyWritten && !errorOccured);

	return fullyWritten && !errorOccured;
}
<commit_msg>Fixed memory leak induced by threads (autocleanud with pthread_detach when thread finishes) on UnixDomainSocketServer.<commit_after>/*************************************************************************
 * libjson-rpc-cpp
 *************************************************************************
 * @file    unixdomainsocketserver.cpp
 * @date    07.05.2015
 * @author  Alexandre Poirot <alexandre.poirot@legrand.fr>
 * @license See attached LICENSE.txt
 ************************************************************************/

#include "unixdomainsocketserver.h"
#include <cstdlib>
#include <sstream>
#include <iostream>
#include <sys/types.h>
#include <jsonrpccpp/common/specificationparser.h>
#include <cstdio>
#include <unistd.h>
#include <string>

using namespace jsonrpc;
using namespace std;

#define BUFFER_SIZE 64
#define PATH_MAX 108
#ifndef DELIMITER_CHAR
#define DELIMITER_CHAR char(0x0A)
#endif //DELIMITER_CHAR

UnixDomainSocketServer::UnixDomainSocketServer(const string &socket_path) :
	AbstractServerConnector(),
	socket_path(socket_path.substr(0, PATH_MAX)),
	running(false)
{
}

bool UnixDomainSocketServer::StartListening()
{
	if(!this->running)
	{
		//Create and bind socket here.
		//Then launch the listenning loop.
		this->socket_fd = socket(AF_UNIX, SOCK_STREAM, 0);
		if(this->socket_fd < 0)
		{
			cerr << "socket() failed" << endl;
			return false;
		}

		unlink(this->socket_path.c_str());

		/* start with a clean address structure */
		memset(&(this->address), 0, sizeof(struct sockaddr_un));

		this->address.sun_family = AF_UNIX;
		snprintf(this->address.sun_path, PATH_MAX, this->socket_path.c_str());

		if(bind(this->socket_fd, reinterpret_cast<struct sockaddr *>(&(this->address)), sizeof(struct sockaddr_un)) != 0)
		{
			cerr << "bind() failed" << endl;
			return false;
		}

		if(listen(this->socket_fd, 5) != 0)
		{
			cerr << "listen() failed" << endl;
			return false;
		}
		//Launch listening loop there
		int ret = pthread_create(&(this->listenning_thread), NULL, UnixDomainSocketServer::LaunchLoop, this);
		if(ret != 0) {
			pthread_detach(this->listenning_thread);
		}
		this->running = static_cast<bool>(ret==0);
	}
	return this->running;
}

bool UnixDomainSocketServer::StopListening()
{
	if(this->running)
	{
		close(this->socket_fd);
		unlink(this->socket_path.c_str());
		this->running = false;
	}
	return true;
}

bool UnixDomainSocketServer::SendResponse(const string& response, void* addInfo)
{
	bool result = false;
	int connection_fd = reinterpret_cast<intptr_t>(addInfo);

	string temp = response;
	if(temp.find(DELIMITER_CHAR) == string::npos) {
		temp.append(1, DELIMITER_CHAR);
	}
	if(DELIMITER_CHAR != '\n') {
		char eot = DELIMITER_CHAR;
		string toSend = temp.substr(0, toSend.find_last_of('\n'));
		toSend += eot;
		result = this->WriteToSocket(connection_fd, toSend);
	}
	else {
		result = this->WriteToSocket(connection_fd, temp);
	}
	close(connection_fd);
	return result;
}

void* UnixDomainSocketServer::LaunchLoop(void *p_data) {
	pthread_detach(pthread_self());
	UnixDomainSocketServer *instance = reinterpret_cast<UnixDomainSocketServer*>(p_data);;
	instance->ListenLoop();
}

void UnixDomainSocketServer::ListenLoop() {
	int connection_fd;
	socklen_t address_length = sizeof(this->address);
	while((connection_fd = accept(this->socket_fd, (struct sockaddr *) &(this->address),  &address_length)) > -1)
	{
		pthread_t client_thread;
		struct GenerateResponseParameters *params = new struct GenerateResponseParameters();
		params->instance = this;
		params->connection_fd = connection_fd;
		int ret = pthread_create(&client_thread, NULL, UnixDomainSocketServer::GenerateResponse, params);
		if(ret != 0) {
			pthread_detach(client_thread);
			delete params;
			params = NULL;
		}
	}
}

void* UnixDomainSocketServer::GenerateResponse(void *p_data) {
	pthread_detach(pthread_self());
	struct GenerateResponseParameters* params = reinterpret_cast<struct GenerateResponseParameters*>(p_data);
	UnixDomainSocketServer *instance = params->instance;
	int connection_fd = params->connection_fd;
	delete params;
	params = NULL;
	int nbytes;
	char buffer[BUFFER_SIZE];
	string request;
	do { //The client sends its json formatted request and a delimiter request.
		nbytes = read(connection_fd, buffer, BUFFER_SIZE);
		request.append(buffer,nbytes);
	} while(request.find(DELIMITER_CHAR) == string::npos);
	instance->OnRequest(request, reinterpret_cast<void*>(connection_fd));
}

bool UnixDomainSocketServer::WriteToSocket(int fd, const string& toWrite) {
	bool fullyWritten = false;
	bool errorOccured = false;
	string toSend = toWrite;
	do {
		ssize_t byteWritten = write(fd, toSend.c_str(), toSend.size());
		if(byteWritten < 0)
			errorOccured = true;
		else if(byteWritten < toSend.size()) {
			int len = toSend.size() - byteWritten;
			toSend = toSend.substr(byteWritten + sizeof(char), len);
		}
		else
			fullyWritten = true;
	} while(!fullyWritten && !errorOccured);

	return fullyWritten && !errorOccured;
}
<|endoftext|>


<commit_before>/**
Copyright (c) 2013, Philip Deegan.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
    * Neither the name of Philip Deegan nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "kul/io.hpp"

#include "maiken/defs.hpp"
#include "maiken/project.hpp"

const kul::yaml::Validator maiken::Project::validator() const{
    using namespace kul::yaml;
    NodeValidator dependencies("dep", {
        NodeValidator("name"),
        NodeValidator("version"),
        NodeValidator("profile"),
        NodeValidator("scm"),
        NodeValidator("local")
    }, 0, NodeType::LIST);

    NodeValidator modules("mod", {
        NodeValidator("name"),
        NodeValidator("version"),
        NodeValidator("profile"),
        NodeValidator("scm"),
        NodeValidator("local"),
        NodeValidator("arg", {
            NodeValidator("compile", { NodeValidator("*") }, 0, NodeType::MAP),
            NodeValidator("link", { NodeValidator("*") }, 0, NodeType::MAP),
            NodeValidator("pack", { NodeValidator("*") }, 0, NodeType::MAP)
        }, 0, NodeType::MAP)
    }, 0, NodeType::LIST);

    NodeValidator env("env", {
        NodeValidator("name", 1),
        NodeValidator("mode", 1),
        NodeValidator("value", 1)
    }, 0, NodeType::LIST);

    NodeValidator if_arg("if_arg", { NodeValidator("*") }, 0, NodeType::MAP);
    NodeValidator if_inc("if_inc", { NodeValidator("*") }, 0, NodeType::MAP);
    NodeValidator if_lib("if_lib", { NodeValidator("*") }, 0, NodeType::MAP);
    NodeValidator if_src("if_src", { NodeValidator("*") }, 0, NodeType::MAP);

    return Validator({
        NodeValidator("name", 1),
        NodeValidator("version"),
        NodeValidator("scm"),
        NodeValidator("property",  {NodeValidator("*")}, 0, NodeType::MAP),
        NodeValidator("super"),
        NodeValidator("parent"),
        NodeValidator("inc"),
        NodeValidator("src"),
        NodeValidator("path"),
        NodeValidator("lib"),
        NodeValidator("link"),
        NodeValidator("lang"),
        NodeValidator("main"),
        NodeValidator("mode"),
        NodeValidator("arg"),
        NodeValidator("install"),
        NodeValidator("self"),
        env,
        dependencies,
        modules,
        if_arg,
        if_inc,
        if_lib,
        if_src,
        NodeValidator("profile", {
            NodeValidator("name", 1),
            NodeValidator("parent"),
            NodeValidator("inc"),
            NodeValidator("src"),
            NodeValidator("path"),
            NodeValidator("lib"),
            NodeValidator("link"),
            NodeValidator("lang"),
            NodeValidator("main"),
            NodeValidator("mode"),
            NodeValidator("arg"),
            NodeValidator("install"),
            NodeValidator("self"),
            env,
            dependencies,
            modules,
            if_arg,
            if_inc,
            if_lib,
            if_src
        }, 0, NodeType::LIST)});
}

void maiken::NewProject::write(){
    {
        kul::io::Writer w(file());
        w.write("\n", true);
        w.write("name: new_mkn_project", true);
        w.write("#inc: ./inc\n#src:  ./src", true);
        w.write("main: cpp.cpp", true);
    }
    {
        kul::io::Writer w("cpp.cpp");
        w.write("\n\n#include <iostream>", true);
        w.write("\n", true);
        w.write("int main(int argc, char* argv[]){", true);
        w.write("\n", true);
        w.write("    std::cout << \"HELLO WORLD!\" << std::endl;", true);
        w.write("\n", true);
        w.write("    return 0;", true);
        w.write("}", true);
    }
}
<commit_msg>allow anything under mod arg<commit_after>/**
Copyright (c) 2013, Philip Deegan.
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:

    * Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
    * Neither the name of Philip Deegan nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "kul/io.hpp"

#include "maiken/defs.hpp"
#include "maiken/project.hpp"

const kul::yaml::Validator maiken::Project::validator() const{
    using namespace kul::yaml;
    NodeValidator dependencies("dep", {
        NodeValidator("name"),
        NodeValidator("version"),
        NodeValidator("profile"),
        NodeValidator("scm"),
        NodeValidator("local")
    }, 0, NodeType::LIST);

    NodeValidator modules("mod", {
        NodeValidator("name"),
        NodeValidator("version"),
        NodeValidator("profile"),
        NodeValidator("scm"),
        NodeValidator("local"),
        NodeValidator("arg", {
            NodeValidator("compile", { NodeValidator("*") }, 0, NodeType::NON),
            NodeValidator("link",    { NodeValidator("*") }, 0, NodeType::NON),
            NodeValidator("pack",    { NodeValidator("*") }, 0, NodeType::NON)
        }, 0, NodeType::MAP)
    }, 0, NodeType::LIST);

    NodeValidator env("env", {
        NodeValidator("name", 1),
        NodeValidator("mode", 1),
        NodeValidator("value", 1)
    }, 0, NodeType::LIST);

    NodeValidator if_arg("if_arg", { NodeValidator("*") }, 0, NodeType::MAP);
    NodeValidator if_inc("if_inc", { NodeValidator("*") }, 0, NodeType::MAP);
    NodeValidator if_lib("if_lib", { NodeValidator("*") }, 0, NodeType::MAP);
    NodeValidator if_src("if_src", { NodeValidator("*") }, 0, NodeType::MAP);

    return Validator({
        NodeValidator("name", 1),
        NodeValidator("version"),
        NodeValidator("scm"),
        NodeValidator("property",  {NodeValidator("*")}, 0, NodeType::MAP),
        NodeValidator("super"),
        NodeValidator("parent"),
        NodeValidator("inc"),
        NodeValidator("src"),
        NodeValidator("path"),
        NodeValidator("lib"),
        NodeValidator("link"),
        NodeValidator("lang"),
        NodeValidator("main"),
        NodeValidator("mode"),
        NodeValidator("arg"),
        NodeValidator("install"),
        NodeValidator("self"),
        env,
        dependencies,
        modules,
        if_arg,
        if_inc,
        if_lib,
        if_src,
        NodeValidator("profile", {
            NodeValidator("name", 1),
            NodeValidator("parent"),
            NodeValidator("inc"),
            NodeValidator("src"),
            NodeValidator("path"),
            NodeValidator("lib"),
            NodeValidator("link"),
            NodeValidator("lang"),
            NodeValidator("main"),
            NodeValidator("mode"),
            NodeValidator("arg"),
            NodeValidator("install"),
            NodeValidator("self"),
            env,
            dependencies,
            modules,
            if_arg,
            if_inc,
            if_lib,
            if_src
        }, 0, NodeType::LIST)});
}

void maiken::NewProject::write(){
    {
        kul::io::Writer w(file());
        w.write("\n", true);
        w.write("name: new_mkn_project", true);
        w.write("#inc: ./inc\n#src:  ./src", true);
        w.write("main: cpp.cpp", true);
    }
    {
        kul::io::Writer w("cpp.cpp");
        w.write("\n\n#include <iostream>", true);
        w.write("\n", true);
        w.write("int main(int argc, char* argv[]){", true);
        w.write("\n", true);
        w.write("    std::cout << \"HELLO WORLD!\" << std::endl;", true);
        w.write("\n", true);
        w.write("    return 0;", true);
        w.write("}", true);
    }
}
<|endoftext|>


<commit_before>/*
 * String allocation.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "pool.hxx"

#include <algorithm>

#include <assert.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

void *
p_memdup_impl(struct pool *pool, const void *src, size_t length
              TRACE_ARGS_DECL)
{
    void *dest = p_malloc_fwd(pool, length);
    memcpy(dest, src, length);
    return dest;
}

char *
p_strdup_impl(struct pool *pool, const char *src
              TRACE_ARGS_DECL)
{
    return (char *)p_memdup_fwd(pool, src, strlen(src) + 1);
}

char *
p_strndup_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL)
{
    char *dest = (char *)p_malloc_fwd(pool, length + 1);
    memcpy(dest, src, length);
    dest[length] = 0;
    return dest;
}

char * gcc_malloc
p_sprintf(struct pool *pool, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    size_t length = (size_t)vsnprintf(nullptr, 0, fmt, ap) + 1;
    va_end(ap);

    char *p = (char *)p_malloc(pool, length);

    va_start(ap, fmt);
    gcc_unused int length2 = vsnprintf(p, length, fmt, ap);
    va_end(ap);

    assert((size_t)length2 + 1 == length);

    return p;
}

char * gcc_malloc
p_strcat(struct pool *pool, const char *first, ...)
{
    va_list ap;

    size_t length = 1;
    va_start(ap, first);
    for (const char *s = first; s != nullptr; s = va_arg(ap, const char *))
        length += strlen(s);
    va_end(ap);

    char *result = (char *)p_malloc(pool, length);

    va_start(ap, first);
    char *p = result;
    for (const char *s = first; s != nullptr; s = va_arg(ap, const char *)) {
        length = strlen(s);
        memcpy(p, s, length);
        p += length;
    }
    va_end(ap);

    *p = 0;

    return result;
}

char * gcc_malloc
p_strncat(struct pool *pool, const char *first, size_t first_length, ...)
{
    va_list ap;

    size_t length = first_length + 1;
    va_start(ap, first_length);
    for (const char *s = va_arg(ap, const char *); s != nullptr;
         s = va_arg(ap, const char *))
        length += va_arg(ap, size_t);
    va_end(ap);

    char *result = (char *)p_malloc(pool, length);

    char *p = result;
    memcpy(p, first, first_length);
    p += first_length;

    va_start(ap, first_length);
    for (const char *s = va_arg(ap, const char *); s != nullptr;
         s = va_arg(ap, const char *)) {
        length = va_arg(ap, size_t);
        memcpy(p, s, length);
        p += length;
    }
    va_end(ap);

    *p = 0;

    return result;
}
<commit_msg>pstring: use mempcpy()<commit_after>/*
 * String allocation.
 *
 * author: Max Kellermann <mk@cm4all.com>
 */

#include "pool.hxx"

#include <algorithm>

#include <assert.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>

static char *
Copy(char *dest, const char *src, size_t n)
{
    return (char *)mempcpy(dest, src, n);
}

void *
p_memdup_impl(struct pool *pool, const void *src, size_t length
              TRACE_ARGS_DECL)
{
    void *dest = p_malloc_fwd(pool, length);
    memcpy(dest, src, length);
    return dest;
}

char *
p_strdup_impl(struct pool *pool, const char *src
              TRACE_ARGS_DECL)
{
    return (char *)p_memdup_fwd(pool, src, strlen(src) + 1);
}

char *
p_strndup_impl(struct pool *pool, const char *src, size_t length TRACE_ARGS_DECL)
{
    char *dest = (char *)p_malloc_fwd(pool, length + 1);
    *Copy(dest, src, length) = 0;
    return dest;
}

char * gcc_malloc
p_sprintf(struct pool *pool, const char *fmt, ...)
{
    va_list ap;
    va_start(ap, fmt);
    size_t length = (size_t)vsnprintf(nullptr, 0, fmt, ap) + 1;
    va_end(ap);

    char *p = (char *)p_malloc(pool, length);

    va_start(ap, fmt);
    gcc_unused int length2 = vsnprintf(p, length, fmt, ap);
    va_end(ap);

    assert((size_t)length2 + 1 == length);

    return p;
}

char * gcc_malloc
p_strcat(struct pool *pool, const char *first, ...)
{
    va_list ap;

    size_t length = 1;
    va_start(ap, first);
    for (const char *s = first; s != nullptr; s = va_arg(ap, const char *))
        length += strlen(s);
    va_end(ap);

    char *result = (char *)p_malloc(pool, length);

    va_start(ap, first);
    char *p = result;
    for (const char *s = first; s != nullptr; s = va_arg(ap, const char *))
        p = Copy(p, s, strlen(s));
    va_end(ap);

    *p = 0;

    return result;
}

char * gcc_malloc
p_strncat(struct pool *pool, const char *first, size_t first_length, ...)
{
    va_list ap;

    size_t length = first_length + 1;
    va_start(ap, first_length);
    for (const char *s = va_arg(ap, const char *); s != nullptr;
         s = va_arg(ap, const char *))
        length += va_arg(ap, size_t);
    va_end(ap);

    char *result = (char *)p_malloc(pool, length);

    char *p = result;
    p = Copy(p, first, first_length);

    va_start(ap, first_length);
    for (const char *s = va_arg(ap, const char *); s != nullptr;
         s = va_arg(ap, const char *))
        p = Copy(p, s, va_arg(ap, size_t));
    va_end(ap);

    *p = 0;

    return result;
}
<|endoftext|>


<commit_before>/*
   Copyright (C) 2009 Red Hat, Inc.

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

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

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"

#include <getopt.h>
#include <iostream>

#include "cmd_line_parser.h"
#include "utils.h"
#include "debug.h"

#define DISABLE_ABBREVIATE

CmdLineParser::Option::Option(int in_id, const std::string& in_name, char in_short_name,
                              OptionType in_type, const std::string& in_help,
                              const std::string& in_arg_name)
    : id (in_id)
    , name (in_name)
    , arg_name (in_arg_name)
    , type (in_type)
    , short_name (in_short_name)
    , help (in_help)
    , optional (true)
    , is_set (false)
    , seperator (0)
{
}

CmdLineParser::CmdLineParser(std::string description, bool allow_positional_args)
    : _description (description)
    , _short_options ("+")
    , _argc (0)
    , _argv (NULL)
    , _multi_args (NULL)
    , _multi_next (NULL)
    , _multi_seperator (0)
    , _positional_args (allow_positional_args)
    , _done (false)
{
}

CmdLineParser::~CmdLineParser()
{
    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        delete *iter;
    }
    delete[] _multi_args;
}

void CmdLineParser::add_private(int id, const std::string& name, char short_name,
                                OptionType type, const std::string& help,
                                const std::string& arg_name)
{
    if (_argv) {
        THROW("unexpected");
    }

    if (find(id)) {
        THROW("exist");
    }

    if (name.size() == 0) {
        THROW("invalid name");
    }

    if (find(name)) {
        THROW("name exist");
    }

    if (short_name != 0) {
        if (!isalnum(short_name) || short_name == 'W') {
            THROW("invalid short name");
        }

        if (find(short_name)) {
            THROW("short name exist");
        }
    }

    if (help.size() == 0) {
        THROW("invalid help string");
    }

    if (help.find_first_of('\t') != std::string::npos) {
        THROW("tab is not allow in help string");
    }

    _options.push_back(new Option(id, name, short_name, type, help, arg_name));
}

void CmdLineParser::add(int id, const std::string& name, const std::string& help, char short_name)
{
    if (id < OPTION_FIRST_AVILABLE) {
        THROW("invalid id");
    }
    add_private(id, name, short_name, NO_ARGUMENT, help, "");
}

void CmdLineParser::add(int id, const std::string& name, const std::string& help,
                        const std::string& arg_name, bool reqired_arg, char short_name)
{
    if (id < OPTION_FIRST_AVILABLE) {
        THROW("invalid id");
    }

    if (arg_name.size() == 0) {
        THROW("invalid arg name");
    }

    add_private(id, name, short_name, reqired_arg ? REQUIRED_ARGUMENT : OPTIONAL_ARGUMENT, help,
                arg_name);
}

void CmdLineParser::set_multi(int id, char seperator)
{
    if (_argv) {
        THROW("unexpected");
    }

    if (!ispunct(seperator)) {
        THROW("invalid seperator");
    }

    Option* opt = find(id);

    if (!opt) {
        THROW("not found");
    }

    if (opt->type == NO_ARGUMENT) {
        THROW("can't set multi for option without argument");
    }

    opt->seperator = seperator;
}

void CmdLineParser::set_reqired(int id)
{
    if (_argv) {
        THROW("unexpected");
    }

    Option* opt = find(id);

    if (!opt) {
        THROW("not found");
    }

    opt->optional = false;
}

CmdLineParser::Option* CmdLineParser::find(int id)
{
    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        if ((*iter)->id == id) {
            return *iter;
        }
    }
    return NULL;
}

bool CmdLineParser::is_set(int id)
{
    Option *opt = find(id);

    if (!opt) {
        THROW("not found");
    }
    return opt->is_set;
}

CmdLineParser::Option* CmdLineParser::find(const std::string& name)
{
    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        if ((*iter)->name == name) {
            return *iter;
        }
    }
    return NULL;
}

CmdLineParser::Option* CmdLineParser::find(char short_name)
{
    if (short_name == 0) {
        return NULL;
    }

    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        if ((*iter)->short_name == short_name) {
            return *iter;
        }
    }
    return NULL;
}

CmdLineParser::Option* CmdLineParser::find_missing_opt()
{
    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        CmdLineParser::Option* opt = *iter;
        if (!opt->optional && !opt->is_set) {
            return opt;
        }
    }
    return NULL;
}

void CmdLineParser::build()
{
    Options::iterator iter = _options.begin();
    _long_options.resize(_options.size() + 1);
    for (int i = 0; iter != _options.end(); ++iter, i++) {
        CmdLineParser::Option* opt = *iter;
        struct option& long_option = _long_options[i];
        long_option.name = opt->name.c_str();
        switch (opt->type) {
        case NO_ARGUMENT:
            long_option.has_arg = no_argument;
            break;
        case OPTIONAL_ARGUMENT:
            long_option.has_arg = optional_argument;
            break;
        case REQUIRED_ARGUMENT:
            long_option.has_arg = required_argument;
            break;
        }
        long_option.flag = &long_option.val;
        long_option.val = opt->id;
        if (opt->short_name != 0) {
            _short_options += opt->short_name;
            switch (opt->type) {
            case OPTIONAL_ARGUMENT:
                _short_options += "::";
                break;
            case REQUIRED_ARGUMENT:
                _short_options += ":";
                break;
            case NO_ARGUMENT:
                break;
            }
        }
    }
    struct option& long_option = _long_options[_long_options.size() - 1];
    long_option.flag = 0;
    long_option.has_arg = 0;
    long_option.name = NULL;
    long_option.val = 0;
}

void CmdLineParser::begin(int argc, char** argv)
{
    if (_argv) {
        THROW("unexpected");
    }

    if (!argv || argc < 1) {
        THROW("invalid args");
    }

    add_private(CmdLineParser::OPTION_HELP, "help", 0, NO_ARGUMENT, "show command help", "");
    opterr = 0;
    _argv = argv;
    _argc = argc;
    build();
}

char* CmdLineParser::start_multi(char *optarg, char seperator)
{
    if (!optarg) {
        return NULL;
    }
    _multi_args = new char[strlen(optarg) + 1];
    _multi_seperator = seperator;
    strcpy(_multi_args, optarg);
    if ((_multi_next = strchr(_multi_args, _multi_seperator))) {
        *(_multi_next++) = 0;
    }
    return _multi_args;
}

char* CmdLineParser::next_multi()
{
    if (!_multi_next) {
        _multi_seperator = 0;
        delete[] _multi_args;
        _multi_args = NULL;
        return NULL;
    }
    char* ret = _multi_next;
    if ((_multi_next = strchr(_multi_next, _multi_seperator))) {
        *(_multi_next++) = 0;
    }

    return ret;
}

int CmdLineParser::get_option(char** val)
{
    CmdLineParser::Option* opt_obj;

    if (!_argv) {
        THROW("unexpected");
    }

    if (_multi_args) {
        THROW("in multi args mode");
    }

    if (_done) {
        THROW("is done");
    }

    int long_index;

    int opt = getopt_long(_argc, _argv, _short_options.c_str(), &_long_options[0], &long_index);

    switch (opt) {
    case 0: {
        if (!(opt_obj = find(_long_options[long_index].val))) {
            THROW("long option no found");
        }

#ifdef DISABLE_ABBREVIATE
        int name_pos = (opt_obj->type == REQUIRED_ARGUMENT) ? optind - 2 : optind - 1;
        std::string cmd_name(_argv[name_pos] + 2);
        if (cmd_name.find(opt_obj->name) != 0) {
            Platform::term_printf("%s: invalid option '--%s'\n", _argv[0], cmd_name.c_str());
            return OPTION_ERROR;
        }
#endif

        if (opt_obj->seperator) {
            *val = start_multi(optarg, opt_obj->seperator);
        } else {
            *val = optarg;
        }
        opt_obj->is_set = true;
        return opt_obj->id;
    }
    case -1: {
        *val = NULL;
        if (!_positional_args && optind != _argc) {
            Platform::term_printf("%s: unexpected positional arguments\n", _argv[0]);
            return OPTION_ERROR;
        }
        if ((opt_obj = find_missing_opt())) {
            Platform::term_printf("%s: option --%s is required\n", _argv[0], opt_obj->name.c_str());
            return OPTION_ERROR;
        }
        _done = true;
        return OPTION_DONE;
    }
    case '?':
        if (optopt >= 255) {
            opt_obj = find(optopt);
            ASSERT(opt_obj);

#ifdef DISABLE_ABBREVIATE
            std::string cmd_name(_argv[optind - 1] + 2);
            if (cmd_name.find(opt_obj->name) != 0) {
                Platform::term_printf("%s: invalid option '--%s'\n", _argv[0], cmd_name.c_str());
                return OPTION_ERROR;
            }
#endif
            Platform::term_printf("%s: option --%s requires an argument\n",
                                  _argv[0], opt_obj->name.c_str());
        } else if (optopt == 0) {
            Platform::term_printf("%s: invalid option '%s'\n", _argv[0], _argv[optind - 1]);
        } else if ((opt_obj = find((char)optopt))) {
            Platform::term_printf("%s: option '-%c' requires an argument\n",
                                  _argv[0], opt_obj->short_name);
        } else {
            Platform::term_printf("%s: invalid option '-%c'\n", _argv[0], char(optopt));
        }
        return OPTION_ERROR;
    default:
        if (opt > 255 || !(opt_obj = find((char)opt))) {
            *val = NULL;
            return OPTION_ERROR;
        }
        if (opt_obj->seperator) {
            *val = start_multi(optarg, opt_obj->seperator);
        } else {
            *val = optarg;
        }
        opt_obj->is_set = true;
        return opt_obj->id;
    }
}

char* CmdLineParser::next_argument()
{
    if (!_argv) {
        THROW("unexpected");
    }

    if (_multi_args) {
        return next_multi();
    }

    if (!_done) {
        THROW("not done");
    }

    if (optind == _argc) {
        return NULL;
    }
    return _argv[optind++];
}

void CmdLineParser::show_help()
{
    static const int HELP_START_POS = 30;
    static const int HELP_WIDTH = 80 - HELP_START_POS;
    std::ostringstream os;

    os << _argv[0] << " - " << _description.c_str() << "\n\noptions:\n\n";

    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        CmdLineParser::Option* opt = *iter;

        if (opt->short_name) {
            os << "  -" << opt->short_name << ", ";
        } else {
            os << "      ";
        }

        os << "--" << opt->name;

        if (opt->type == OPTIONAL_ARGUMENT) {
            os << "[=";
        } else if (opt->type == REQUIRED_ARGUMENT) {
            os << " <";
        }

        if (opt->type == OPTIONAL_ARGUMENT || opt->type == REQUIRED_ARGUMENT) {
            if (opt->seperator) {
                os << opt->arg_name << opt->seperator << opt->arg_name << "...";
            } else {
                os << opt->arg_name;
            }
        }

        if (opt->type == OPTIONAL_ARGUMENT) {
            os << "]";
        } else if (opt->type == REQUIRED_ARGUMENT) {
            os << ">";
        }

        int skip = HELP_START_POS - os.str().size();
        if (skip < 2) {
            os << "\n                              ";
        } else {
            while (skip--) {
                os << " ";
            }
        }

        int line_count = 0;
        std::istringstream is(opt->help);
        std::string line;
        std::getline(is, line);
        do {
            if (line_count++) {
                os << "                              ";
            }
            if (line.size() > HELP_WIDTH) {
                int now = HELP_WIDTH;
                std::string sub;
                sub.append(line, 0, now);
                int last_space;
                if ((last_space = sub.find_last_of(' ')) != std::string::npos) {
                    now = last_space;
                    sub.resize(now++);
                }
                os << sub << "\n";
                line = line.substr(now, line.size() - now);
            } else {
                os << line << "\n";
                line.clear();
            }
        } while (line.size() || std::getline(is, line));
    }

    os << "\n";
    Platform::term_printf(os.str().c_str());
}

<commit_msg>spicec: enable multiple CmdLineParser instantiations<commit_after>/*
   Copyright (C) 2009 Red Hat, Inc.

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

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

   You should have received a copy of the GNU Lesser General Public
   License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/

#include "common.h"

#include <getopt.h>
#include <iostream>

#include "cmd_line_parser.h"
#include "utils.h"
#include "debug.h"

#define DISABLE_ABBREVIATE

CmdLineParser::Option::Option(int in_id, const std::string& in_name, char in_short_name,
                              OptionType in_type, const std::string& in_help,
                              const std::string& in_arg_name)
    : id (in_id)
    , name (in_name)
    , arg_name (in_arg_name)
    , type (in_type)
    , short_name (in_short_name)
    , help (in_help)
    , optional (true)
    , is_set (false)
    , seperator (0)
{
}

CmdLineParser::CmdLineParser(std::string description, bool allow_positional_args)
    : _description (description)
    , _short_options ("+")
    , _argc (0)
    , _argv (NULL)
    , _multi_args (NULL)
    , _multi_next (NULL)
    , _multi_seperator (0)
    , _positional_args (allow_positional_args)
    , _done (false)
{
    //Enables multiple instantiations. One at a time, not thread-safe.
    optind = 1;
    opterr = 1;
    optopt = 0;
    optarg = 0;
}

CmdLineParser::~CmdLineParser()
{
    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        delete *iter;
    }
    delete[] _multi_args;
}

void CmdLineParser::add_private(int id, const std::string& name, char short_name,
                                OptionType type, const std::string& help,
                                const std::string& arg_name)
{
    if (_argv) {
        THROW("unexpected");
    }

    if (find(id)) {
        THROW("exist");
    }

    if (name.size() == 0) {
        THROW("invalid name");
    }

    if (find(name)) {
        THROW("name exist");
    }

    if (short_name != 0) {
        if (!isalnum(short_name) || short_name == 'W') {
            THROW("invalid short name");
        }

        if (find(short_name)) {
            THROW("short name exist");
        }
    }

    if (help.size() == 0) {
        THROW("invalid help string");
    }

    if (help.find_first_of('\t') != std::string::npos) {
        THROW("tab is not allow in help string");
    }

    _options.push_back(new Option(id, name, short_name, type, help, arg_name));
}

void CmdLineParser::add(int id, const std::string& name, const std::string& help, char short_name)
{
    if (id < OPTION_FIRST_AVILABLE) {
        THROW("invalid id");
    }
    add_private(id, name, short_name, NO_ARGUMENT, help, "");
}

void CmdLineParser::add(int id, const std::string& name, const std::string& help,
                        const std::string& arg_name, bool reqired_arg, char short_name)
{
    if (id < OPTION_FIRST_AVILABLE) {
        THROW("invalid id");
    }

    if (arg_name.size() == 0) {
        THROW("invalid arg name");
    }

    add_private(id, name, short_name, reqired_arg ? REQUIRED_ARGUMENT : OPTIONAL_ARGUMENT, help,
                arg_name);
}

void CmdLineParser::set_multi(int id, char seperator)
{
    if (_argv) {
        THROW("unexpected");
    }

    if (!ispunct(seperator)) {
        THROW("invalid seperator");
    }

    Option* opt = find(id);

    if (!opt) {
        THROW("not found");
    }

    if (opt->type == NO_ARGUMENT) {
        THROW("can't set multi for option without argument");
    }

    opt->seperator = seperator;
}

void CmdLineParser::set_reqired(int id)
{
    if (_argv) {
        THROW("unexpected");
    }

    Option* opt = find(id);

    if (!opt) {
        THROW("not found");
    }

    opt->optional = false;
}

CmdLineParser::Option* CmdLineParser::find(int id)
{
    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        if ((*iter)->id == id) {
            return *iter;
        }
    }
    return NULL;
}

bool CmdLineParser::is_set(int id)
{
    Option *opt = find(id);

    if (!opt) {
        THROW("not found");
    }
    return opt->is_set;
}

CmdLineParser::Option* CmdLineParser::find(const std::string& name)
{
    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        if ((*iter)->name == name) {
            return *iter;
        }
    }
    return NULL;
}

CmdLineParser::Option* CmdLineParser::find(char short_name)
{
    if (short_name == 0) {
        return NULL;
    }

    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        if ((*iter)->short_name == short_name) {
            return *iter;
        }
    }
    return NULL;
}

CmdLineParser::Option* CmdLineParser::find_missing_opt()
{
    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        CmdLineParser::Option* opt = *iter;
        if (!opt->optional && !opt->is_set) {
            return opt;
        }
    }
    return NULL;
}

void CmdLineParser::build()
{
    Options::iterator iter = _options.begin();
    _long_options.resize(_options.size() + 1);
    for (int i = 0; iter != _options.end(); ++iter, i++) {
        CmdLineParser::Option* opt = *iter;
        struct option& long_option = _long_options[i];
        long_option.name = opt->name.c_str();
        switch (opt->type) {
        case NO_ARGUMENT:
            long_option.has_arg = no_argument;
            break;
        case OPTIONAL_ARGUMENT:
            long_option.has_arg = optional_argument;
            break;
        case REQUIRED_ARGUMENT:
            long_option.has_arg = required_argument;
            break;
        }
        long_option.flag = &long_option.val;
        long_option.val = opt->id;
        if (opt->short_name != 0) {
            _short_options += opt->short_name;
            switch (opt->type) {
            case OPTIONAL_ARGUMENT:
                _short_options += "::";
                break;
            case REQUIRED_ARGUMENT:
                _short_options += ":";
                break;
            case NO_ARGUMENT:
                break;
            }
        }
    }
    struct option& long_option = _long_options[_long_options.size() - 1];
    long_option.flag = 0;
    long_option.has_arg = 0;
    long_option.name = NULL;
    long_option.val = 0;
}

void CmdLineParser::begin(int argc, char** argv)
{
    if (_argv) {
        THROW("unexpected");
    }

    if (!argv || argc < 1) {
        THROW("invalid args");
    }

    add_private(CmdLineParser::OPTION_HELP, "help", 0, NO_ARGUMENT, "show command help", "");
    opterr = 0;
    _argv = argv;
    _argc = argc;
    build();
}

char* CmdLineParser::start_multi(char *optarg, char seperator)
{
    if (!optarg) {
        return NULL;
    }
    _multi_args = new char[strlen(optarg) + 1];
    _multi_seperator = seperator;
    strcpy(_multi_args, optarg);
    if ((_multi_next = strchr(_multi_args, _multi_seperator))) {
        *(_multi_next++) = 0;
    }
    return _multi_args;
}

char* CmdLineParser::next_multi()
{
    if (!_multi_next) {
        _multi_seperator = 0;
        delete[] _multi_args;
        _multi_args = NULL;
        return NULL;
    }
    char* ret = _multi_next;
    if ((_multi_next = strchr(_multi_next, _multi_seperator))) {
        *(_multi_next++) = 0;
    }

    return ret;
}

int CmdLineParser::get_option(char** val)
{
    CmdLineParser::Option* opt_obj;

    if (!_argv) {
        THROW("unexpected");
    }

    if (_multi_args) {
        THROW("in multi args mode");
    }

    if (_done) {
        THROW("is done");
    }

    int long_index;

    int opt = getopt_long(_argc, _argv, _short_options.c_str(), &_long_options[0], &long_index);

    switch (opt) {
    case 0: {
        if (!(opt_obj = find(_long_options[long_index].val))) {
            THROW("long option no found");
        }

#ifdef DISABLE_ABBREVIATE
        int name_pos = (opt_obj->type == REQUIRED_ARGUMENT) ? optind - 2 : optind - 1;
        std::string cmd_name(_argv[name_pos] + 2);
        if (cmd_name.find(opt_obj->name) != 0) {
            Platform::term_printf("%s: invalid option '--%s'\n", _argv[0], cmd_name.c_str());
            return OPTION_ERROR;
        }
#endif

        if (opt_obj->seperator) {
            *val = start_multi(optarg, opt_obj->seperator);
        } else {
            *val = optarg;
        }
        opt_obj->is_set = true;
        return opt_obj->id;
    }
    case -1: {
        *val = NULL;
        if (!_positional_args && optind != _argc) {
            Platform::term_printf("%s: unexpected positional arguments\n", _argv[0]);
            return OPTION_ERROR;
        }
        if ((opt_obj = find_missing_opt())) {
            Platform::term_printf("%s: option --%s is required\n", _argv[0], opt_obj->name.c_str());
            return OPTION_ERROR;
        }
        _done = true;
        return OPTION_DONE;
    }
    case '?':
        if (optopt >= 255) {
            opt_obj = find(optopt);
            ASSERT(opt_obj);

#ifdef DISABLE_ABBREVIATE
            std::string cmd_name(_argv[optind - 1] + 2);
            if (cmd_name.find(opt_obj->name) != 0) {
                Platform::term_printf("%s: invalid option '--%s'\n", _argv[0], cmd_name.c_str());
                return OPTION_ERROR;
            }
#endif
            Platform::term_printf("%s: option --%s requires an argument\n",
                                  _argv[0], opt_obj->name.c_str());
        } else if (optopt == 0) {
            Platform::term_printf("%s: invalid option '%s'\n", _argv[0], _argv[optind - 1]);
        } else if ((opt_obj = find((char)optopt))) {
            Platform::term_printf("%s: option '-%c' requires an argument\n",
                                  _argv[0], opt_obj->short_name);
        } else {
            Platform::term_printf("%s: invalid option '-%c'\n", _argv[0], char(optopt));
        }
        return OPTION_ERROR;
    default:
        if (opt > 255 || !(opt_obj = find((char)opt))) {
            *val = NULL;
            return OPTION_ERROR;
        }
        if (opt_obj->seperator) {
            *val = start_multi(optarg, opt_obj->seperator);
        } else {
            *val = optarg;
        }
        opt_obj->is_set = true;
        return opt_obj->id;
    }
}

char* CmdLineParser::next_argument()
{
    if (!_argv) {
        THROW("unexpected");
    }

    if (_multi_args) {
        return next_multi();
    }

    if (!_done) {
        THROW("not done");
    }

    if (optind == _argc) {
        return NULL;
    }
    return _argv[optind++];
}

void CmdLineParser::show_help()
{
    static const int HELP_START_POS = 30;
    static const int HELP_WIDTH = 80 - HELP_START_POS;
    std::ostringstream os;

    os << _argv[0] << " - " << _description.c_str() << "\n\noptions:\n\n";

    Options::iterator iter = _options.begin();
    for (; iter != _options.end(); ++iter) {
        CmdLineParser::Option* opt = *iter;

        if (opt->short_name) {
            os << "  -" << opt->short_name << ", ";
        } else {
            os << "      ";
        }

        os << "--" << opt->name;

        if (opt->type == OPTIONAL_ARGUMENT) {
            os << "[=";
        } else if (opt->type == REQUIRED_ARGUMENT) {
            os << " <";
        }

        if (opt->type == OPTIONAL_ARGUMENT || opt->type == REQUIRED_ARGUMENT) {
            if (opt->seperator) {
                os << opt->arg_name << opt->seperator << opt->arg_name << "...";
            } else {
                os << opt->arg_name;
            }
        }

        if (opt->type == OPTIONAL_ARGUMENT) {
            os << "]";
        } else if (opt->type == REQUIRED_ARGUMENT) {
            os << ">";
        }

        int skip = HELP_START_POS - os.str().size();
        if (skip < 2) {
            os << "\n                              ";
        } else {
            while (skip--) {
                os << " ";
            }
        }

        int line_count = 0;
        std::istringstream is(opt->help);
        std::string line;
        std::getline(is, line);
        do {
            if (line_count++) {
                os << "                              ";
            }
            if (line.size() > HELP_WIDTH) {
                int now = HELP_WIDTH;
                std::string sub;
                sub.append(line, 0, now);
                int last_space;
                if ((last_space = sub.find_last_of(' ')) != std::string::npos) {
                    now = last_space;
                    sub.resize(now++);
                }
                os << sub << "\n";
                line = line.substr(now, line.size() - now);
            } else {
                os << line << "\n";
                line.clear();
            }
        } while (line.size() || std::getline(is, line));
    }

    os << "\n";
    Platform::term_printf(os.str().c_str());
}

<|endoftext|>


<commit_before>// -*-Mode: C++;-*-

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// --------------------------------------------------------------------------
// Part of HPCToolkit (hpctoolkit.org)
//
// Information about sources of support for research and development of
// HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
// --------------------------------------------------------------------------
//
// Copyright ((c)) 2002-2017, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) 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 RICE 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 RICE 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.
//
// ******************************************************* EndRiceCopyright *

#include <lib/prof-lean/hpcrun-fmt.h> // metric stuffs
#include <lib/support/VarMap.hpp>

#define VAR_PREFIX '$'

VarMap::VarMap(hpcrun_metricVal_t *metrics, metric_desc_t* list_metric_desc,
   size_t num_metrics)
{
  m_metrics          = metrics;
  m_list_metric_desc = list_metric_desc;
  m_error_code       = 0;
  m_num_metrics      = num_metrics;
}

bool VarMap::isVariable(char *expr)
{
  return (expr[0] == VAR_PREFIX);
}

double VarMap::getValue(int var)
{
  if ( var>=0 && var<m_num_metrics );
    return hpcrun_fmt_metric_get_value(m_list_metric_desc[var],
              m_metrics[var]);
  m_error_code = 1;
  return (double) var;
}

int
VarMap::getErrorCode()
{
   return m_error_code;
}

<commit_msg>Minor bug fix in computing math expression<commit_after>// -*-Mode: C++;-*-

// * BeginRiceCopyright *****************************************************
//
// $HeadURL$
// $Id$
//
// --------------------------------------------------------------------------
// Part of HPCToolkit (hpctoolkit.org)
//
// Information about sources of support for research and development of
// HPCToolkit is at 'hpctoolkit.org' and in 'README.Acknowledgments'.
// --------------------------------------------------------------------------
//
// Copyright ((c)) 2002-2017, Rice University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
//   notice, this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright
//   notice, this list of conditions and the following disclaimer in the
//   documentation and/or other materials provided with the distribution.
//
// * Neither the name of Rice University (RICE) 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 RICE 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 RICE 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.
//
// ******************************************************* EndRiceCopyright *

#include <lib/prof-lean/hpcrun-fmt.h> // metric stuffs
#include <lib/support/VarMap.hpp>

#define VAR_PREFIX '$'

VarMap::VarMap(hpcrun_metricVal_t *metrics, metric_desc_t* list_metric_desc,
   size_t num_metrics)
{
  m_metrics          = metrics;
  m_list_metric_desc = list_metric_desc;
  m_error_code       = 0;
  m_num_metrics      = num_metrics;
}

bool VarMap::isVariable(char *expr)
{
  return (expr[0] == VAR_PREFIX);
}

double VarMap::getValue(int var)
{
  if ( var>=0 && var<m_num_metrics )
    return hpcrun_fmt_metric_get_value(m_list_metric_desc[var],
              m_metrics[var]);
  m_error_code = 1;
  return (double) var;
}

int
VarMap::getErrorCode()
{
   return m_error_code;
}

<|endoftext|>


<commit_before>/*!
\file ibpm.cc

\brief Sample main routine for IBFS code

\author Clancy Rowley
\date  3 Jul 2008

$Revision$
$Date$
$Author$
$HeadURL$
*/

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include "ibpm.h"

using namespace std;
using namespace ibpm;

enum ModelType { LINEAR, NONLINEAR, ADJOINT, LINEARPERIODIC, SFD, INVALID };

// Return the type of model specified in the string modelName
ModelType str2model( string modelName );

// Return the integration scheme specified in the string integratorType
Scheme::SchemeType str2scheme( string integratorType );

/*! \brief Main routine for IBFS code
 *  Set up a timestepper and advance the flow in time.
 */
int main(int argc, char* argv[]) {
    cout << "Immersed Boundary Projection Method (IBPM), version "
        << IBPM_VERSION << "\n" << endl;

    // Get parameters
    ParmParser parser( argc, argv );
    bool helpFlag = parser.getFlag( "h", "print this help message and exit" );
    string name = parser.getString( "name", "run name", "ibpm" );
    int nx = parser.getInt(
        "nx", "number of gridpoints in x-direction", 200 );
    int ny = parser.getInt(
        "ny", "number of gridpoints in y-direction", 200 );
    int ngrid = parser.getInt(
        "ngrid", "number of grid levels for multi-domain scheme", 1 );
    double length = parser.getDouble(
        "length", "length of finest domain in x-dir", 4.0 );
    double xOffset = parser.getDouble(
        "xoffset", "x-coordinate of left edge of finest domain", -2. );
    double yOffset = parser.getDouble(
        "yoffset", "y-coordinate of bottom edge of finest domain", -2. );
	double xShift = parser.getDouble(
		"xshift", "percentage offset between grid levels in x-direction", 0. );
    double yShift = parser.getDouble(
		"yshift", "percentage offset between grid levels in y-direction", 0. );
    string geomFile = parser.getString(
        "geom", "filename for reading geometry", name + ".geom" );
    double Reynolds = parser.getDouble("Re", "Reynolds number", 100.);
    double dt = parser.getDouble( "dt", "timestep", 0.02 );
    string modelName = parser.getString(
        "model", "type of model (linear, nonlinear, adjoint, linearperiodic, sfd)",
		"nonlinear" );
    string baseFlow = parser.getString(
        "baseflow", "base flow for linear/adjoint model", "" );
    string integratorType = parser.getString(
        "scheme", "timestepping scheme (euler,ab2,rk3,rk3b)", "rk3" );
    string icFile = parser.getString( "ic", "initial condition filename", "");
    string outdir = parser.getString(
        "outdir", "directory for saving output", "." );
    int iTecplot = parser.getInt(
        "tecplot", "if >0, write a Tecplot file every n timesteps", 100);
    int iRestart = parser.getInt(
        "restart", "if >0, write a restart file every n timesteps", 100);
    int iForce = parser.getInt(
        "force", "if >0, write forces every n timesteps", 1);
    int iEnergy = parser.getInt( "energy", "if >0, write forces every n timesteps", 0);
    int numSteps = parser.getInt(
        "nsteps", "number of timesteps to compute", 250 );
	int period = parser.getInt(
		"period", "period of periodic baseflow", 1);
	int periodStart = parser.getInt(
		"periodstart", "start time of periodic baseflow", 0);
	string periodBaseFlowName = parser.getString(
		"pbaseflowname", "name of periodic baseflow, e.g. 'flow/ibpmperiodic%05d.bin', with '%05d' as time, decided by periodstart/period", "" );
    bool subtractBaseflow = parser.getBool(
		"subbaseflow", "Subtract ic by baseflow (1/0(true/false))", false);
    bool resetTime = parser.getBool( "resettime", "Reset time when subtracting ic by baseflow (1/0(true/false))", false);
    double chi = parser.getDouble( "chi", "sfd gain", 0.02 );
	double Delta = parser.getDouble( "Delta", "sfd cutoff frequency", 15. );
	string numDigitInFileName = parser.getString(
		"numdigfilename", "number of digits for time representation in filename", "%05d");

	ModelType modelType = str2model( modelName );
	Scheme::SchemeType schemeType = str2scheme( integratorType );

    if ( ! parser.inputIsValid() || modelType == INVALID || helpFlag ) {
        parser.printUsage( cerr );
        exit(1);
    }

	// modify this long if statement?
    if ( ( modelType != NONLINEAR ) && ( modelType != SFD ) ) {
		if (modelType != LINEARPERIODIC && baseFlow == "" ){
			cout << "ERROR: for linear or adjoint models, "
            "must specify a base flow" << endl;
			exit(1);
		}
		else if (modelType != LINEARPERIODIC && periodBaseFlowName != ""){
			cout << "WARNING: for linear or adjoint models, "
            "a periodic base flow is not needed" << endl;
			exit(1);
		}
		else if (modelType == LINEARPERIODIC && periodBaseFlowName == "" ) {
			cout << "ERROR: for linear periodic model, "
			"must specify a periodic base flow" << endl;
			exit(1);
		}
		else if (modelType == LINEARPERIODIC && baseFlow != "" ) {
			cout << "WARNING: for linear periodic model, "
            "a single baseflow is not needed" << endl;
			exit(1);
		}
    }

    // create output directory if not already present
    AddSlashToPath( outdir );
    mkdir( outdir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO );

    // output command line arguments
    string cmd = parser.getParameters();
    cout << "Command:" << endl << cmd << "\n" << endl;
    parser.saveParameters( outdir + name + ".cmd" );

    // Name of this run
    cout << "Run name: " << name << "\n" << endl;

    // Setup grid
    cout << "Grid parameters:" << endl
        << "    nx      " << nx << endl
        << "    ny      " << ny << endl
        << "    ngrid   " << ngrid << endl
        << "    length  " << length << endl
        << "    xoffset " << xOffset << endl
		<< "    yoffset " << yOffset << endl
		<< "    xshift  " << xShift << endl
		<< "    yshift  " << yShift << endl
        << endl;
    Grid grid( nx, ny, ngrid, length, xOffset, yOffset );
	grid.setXShift( xShift );
	grid.setYShift( yShift );

    // Setup geometry
    Geometry geom;
    cout << "Reading geometry from file " << geomFile << endl;
    if ( geom.load( geomFile ) ) {
        cout << "    " << geom.getNumPoints() << " points on the boundary" << "\n" << endl;
    }
    else {
        exit(-1);
    }

    // Setup equations to solve
    cout << "Reynolds number = " << Reynolds << "\n" << endl;
    cout << "Setting up Immersed Boundary Solver..." << flush;
    double magnitude = 1;
    double alpha = 0;  // angle of background flow
    Flux q_potential = Flux::UniformFlow( grid, magnitude, alpha );

    NavierStokesModel* model = NULL;
    IBSolver* solver = NULL;
    SFDSolver* SFDsolver = NULL;
	State x00( grid, geom.getNumPoints() );

	switch (modelType){
		case NONLINEAR:
            model =  new NavierStokesModel( grid, geom, Reynolds, q_potential );
			solver = new NonlinearIBSolver( grid, *model, dt, schemeType );
			break;
		case LINEAR:
            if ( ! x00.load( baseFlow ) ) {
                cout << "baseflow failed to load.  Exiting program." << endl;
                exit(1);
            }
            model =  new NavierStokesModel( grid, geom, Reynolds );
			solver = new LinearizedIBSolver( grid, *model, dt, schemeType, x00 );
			break;
		case ADJOINT:
            if ( ! x00.load( baseFlow ) ) {
                cout << "baseflow failed to load.  Exiting program." << endl;
                exit(1);
            }
            model =  new NavierStokesModel( grid, geom, Reynolds );
			solver = new AdjointIBSolver( grid, *model, dt, schemeType, x00 );
			break;
		case LINEARPERIODIC:{
			// load periodic baseflow files
			vector<State> x0(period, x00);
			char pbffilename[256];
			string pbf = periodBaseFlowName;
			for (int i=0; i < period; i++) {
				//cout << "loading the " << i << "-th periodic baseflow:" << endl;
				sprintf(pbffilename, pbf.c_str(), i + periodStart);
				x0[i].load(pbffilename);
			}
			x00 = x0[0];
            model =  new NavierStokesModel( grid, geom, Reynolds );
			solver = new LinearizedPeriodicIBSolver( grid, *model, dt, schemeType, x0, period ) ;
			break;
			}
		case SFD:{
            cout << "SFD parameters:" << endl;
            cout << "    chi =   " << chi << endl;
            cout << "    Delta = " << Delta << endl << endl;
            model =  new NavierStokesModel( grid, geom, Reynolds, q_potential );
			SFDsolver = new SFDSolver( grid, *model, dt, schemeType, Delta, chi ) ;
            solver = SFDsolver;
			break;
			}
		case INVALID:
			cout << "ERROR: must specify a valid modelType" << endl;
			exit(1);
			break;
	}

	assert( model != NULL );
    assert( solver != NULL );
    if( chi != 0 ) {
        assert( SFDsolver != null );
    }
    model->init();

    // Setup timestepper
    cout << "using " << solver->getName() << " timestepper" << endl;
    cout << "    dt = " << dt << "\n" << endl;
	if ( ! solver->load( outdir + name ) ) {
        // Set the tolerance for a ConjugateGradient solver below
        // Otherwise default is tol = 1e-7
        // solver->setTol( 1e-8 )
        solver->init();
        solver->save( outdir + name );
    }

    // Load initial condition
    State x( grid, geom.getNumPoints() );
    x.omega = 0.;
    x.f = 0.;
    x.q = 0.;
	if (icFile != "") {
	    cout << "Loading initial condition from file: " << icFile << endl;
        if ( ! x.load(icFile) ) {
            cout << "    (failed: using zero initial condition)" << endl;
        }
		if ( subtractBaseflow == true ) {
            cout << "    Subtracting initial condition by baseflow to form a linear initial perturbation" << endl;
			if (modelType != NONLINEAR) {
				assert((x.q).Ngrid() == (x00.q).Ngrid());
				assert((x.omega).Ngrid() == (x00.omega).Ngrid());
				x.q -= x00.q;
				x.omega -= x00.omega;
				x.f = 0;
			}
			else {
				cout << "Flag subbaseflow should be true only for linear cases"<< endl;
				exit(1);
			}
            if (resetTime == true) {
                x.timestep = 0;
                x.time = 0.;
            }
		}

        if ( chi != 0.0 ) {
            SFDsolver->loadFilteredState( icFile );
        }

    }
    else {
        cout << "Using zero initial condition" << endl;
    }
    // Calculate flux for state, in case only vorticity was saved
    model->refreshState( x );

	cout << endl << "Initial timestep = " << x.timestep << "\n" << endl;

    // Setup output routines
    OutputTecplot tecplot( outdir + name + numDigitInFileName + ".plt", "Test run, step" +  numDigitInFileName);
    OutputRestart restart( outdir + name + numDigitInFileName + ".bin" );
    OutputForce force( outdir + name + ".force" );
    OutputEnergy energy( outdir + name + ".energy" );

    Logger logger;
    // Output Tecplot file every timestep
    if ( iTecplot > 0 ) {
        cout << "Writing Tecplot file every " << iTecplot << " step(s)" << endl;
        logger.addOutput( &tecplot, iTecplot );
    }
    if ( iRestart > 0 ) {
        cout << "Writing restart file every " << iRestart << " step(s)" << endl;
        logger.addOutput( &restart, iRestart );
    }
    if ( iForce > 0 ) {
        cout << "Writing forces every " << iForce << " step(s)" << endl;
        logger.addOutput( &force, iForce );
    }
    if ( iEnergy > 0 ) {
        cout << "Writing energy every " << iForce << " step(s)" << endl;
        logger.addOutput( &energy, iEnergy );
    }
    cout << endl;
    logger.init();
    logger.doOutput( x );

    cout << "Integrating for " << numSteps << " steps" << endl;
    for(int i=1; i <= numSteps; ++i) {
        cout << "\nstep " << i << endl;
        State xtemp( x ); // For SFD norm calculation

		solver->advance( x );
        double lift;
        double drag;
        x.computeNetForce( drag, lift );
        cout << "    x force: " << setw(16) << drag*2 << ", y force: "
            << setw(16) << lift*2 << "\n";
        logger.doOutput( x );

        // For SFD
        if( chi!= 0.0 ) {
            Scalar dx = xtemp.omega-x.omega;
            double twoNorm = sqrt(InnerProduct(dx, dx)) / dt;

            if ( (x.timestep % iRestart == 0 ) && (chi != 0.0) ) {
                SFDsolver->saveFilteredState( outdir, name, numDigitInFileName );
            }

            cout << "    ||dx||/dt = " << setw(13) << twoNorm << endl;
        }

    }
    logger.cleanup();

	delete solver;
    return 0;
}

ModelType str2model( string modelName ) {
    ModelType type;
    MakeLowercase( modelName );

    if ( modelName == "nonlinear" ) {
        type = NONLINEAR;
    }
    else if ( modelName == "linear" ) {
        type = LINEAR;
    }
    else if ( modelName == "adjoint" ) {
        type = ADJOINT;
    }
	else if ( modelName == "linearperiodic" ) {
        type = LINEARPERIODIC;
    }
	else if ( modelName == "sfd" ) {
		type = SFD;
	}
    else {
        cerr << "Unrecognized model: " << modelName << endl;
        type = INVALID;
    }
    return type;
}

Scheme::SchemeType str2scheme( string schemeName ) {
	Scheme::SchemeType type;
    MakeLowercase( schemeName );
    if ( schemeName == "euler" ) {
        type = Scheme::EULER;
    }
    else if ( schemeName == "ab2" ) {
        type = Scheme::AB2;
    }
    else if ( schemeName == "rk3" ) {
        type = Scheme::RK3;
    }
    else if ( schemeName == "rk3b" ) {
        type = Scheme::RK3b;
    }
    else {
        cerr << "Unrecognized integration scheme: " << schemeName;
		cerr << "    Exiting program." << endl;
        exit(1);
    }
    return type;
}

<commit_msg>Fixed bug in ibpm.cc.  Previous changes to save/load SFD filtered state caused bus errors when restarting other simulations.  Changed the conditions on the save/load of xhat to be dependent on the model type (nonlinear, linear, sfd, etc.) rather than the value of chi.<commit_after>/*!
\file ibpm.cc

\brief Sample main routine for IBFS code

\author Clancy Rowley
\date  3 Jul 2008

$Revision$
$Date$
$Author$
$HeadURL$
*/

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <sys/stat.h>
#include "ibpm.h"

using namespace std;
using namespace ibpm;

enum ModelType { LINEAR, NONLINEAR, ADJOINT, LINEARPERIODIC, SFD, INVALID };

// Return the type of model specified in the string modelName
ModelType str2model( string modelName );

// Return the integration scheme specified in the string integratorType
Scheme::SchemeType str2scheme( string integratorType );

/*! \brief Main routine for IBFS code
 *  Set up a timestepper and advance the flow in time.
 */
int main(int argc, char* argv[]) {
    cout << "Immersed Boundary Projection Method (IBPM), version "
        << IBPM_VERSION << "\n" << endl;

    // Get parameters
    ParmParser parser( argc, argv );
    bool helpFlag = parser.getFlag( "h", "print this help message and exit" );
    string name = parser.getString( "name", "run name", "ibpm" );
    int nx = parser.getInt(
        "nx", "number of gridpoints in x-direction", 200 );
    int ny = parser.getInt(
        "ny", "number of gridpoints in y-direction", 200 );
    int ngrid = parser.getInt(
        "ngrid", "number of grid levels for multi-domain scheme", 1 );
    double length = parser.getDouble(
        "length", "length of finest domain in x-dir", 4.0 );
    double xOffset = parser.getDouble(
        "xoffset", "x-coordinate of left edge of finest domain", -2. );
    double yOffset = parser.getDouble(
        "yoffset", "y-coordinate of bottom edge of finest domain", -2. );
	double xShift = parser.getDouble(
		"xshift", "percentage offset between grid levels in x-direction", 0. );
    double yShift = parser.getDouble(
		"yshift", "percentage offset between grid levels in y-direction", 0. );
    string geomFile = parser.getString(
        "geom", "filename for reading geometry", name + ".geom" );
    double Reynolds = parser.getDouble("Re", "Reynolds number", 100.);
    double dt = parser.getDouble( "dt", "timestep", 0.02 );
    string modelName = parser.getString(
        "model", "type of model (linear, nonlinear, adjoint, linearperiodic, sfd)",
		"nonlinear" );
    string baseFlow = parser.getString(
        "baseflow", "base flow for linear/adjoint model", "" );
    string integratorType = parser.getString(
        "scheme", "timestepping scheme (euler,ab2,rk3,rk3b)", "rk3" );
    string icFile = parser.getString( "ic", "initial condition filename", "");
    string outdir = parser.getString(
        "outdir", "directory for saving output", "." );
    int iTecplot = parser.getInt(
        "tecplot", "if >0, write a Tecplot file every n timesteps", 100);
    int iRestart = parser.getInt(
        "restart", "if >0, write a restart file every n timesteps", 100);
    int iForce = parser.getInt(
        "force", "if >0, write forces every n timesteps", 1);
    int iEnergy = parser.getInt( "energy", "if >0, write forces every n timesteps", 0);
    int numSteps = parser.getInt(
        "nsteps", "number of timesteps to compute", 250 );
	int period = parser.getInt(
		"period", "period of periodic baseflow", 1);
	int periodStart = parser.getInt(
		"periodstart", "start time of periodic baseflow", 0);
	string periodBaseFlowName = parser.getString(
		"pbaseflowname", "name of periodic baseflow, e.g. 'flow/ibpmperiodic%05d.bin', with '%05d' as time, decided by periodstart/period", "" );
    bool subtractBaseflow = parser.getBool(
		"subbaseflow", "Subtract ic by baseflow (1/0(true/false))", false);
    bool resetTime = parser.getBool( "resettime", "Reset time when subtracting ic by baseflow (1/0(true/false))", false);
    double chi = parser.getDouble( "chi", "sfd gain", 0.02 );
	double Delta = parser.getDouble( "Delta", "sfd cutoff frequency", 15. );
	string numDigitInFileName = parser.getString(
		"numdigfilename", "number of digits for time representation in filename", "%05d");

	ModelType modelType = str2model( modelName );
	Scheme::SchemeType schemeType = str2scheme( integratorType );

    if ( ! parser.inputIsValid() || modelType == INVALID || helpFlag ) {
        parser.printUsage( cerr );
        exit(1);
    }

	// modify this long if statement?
    if ( ( modelType != NONLINEAR ) && ( modelType != SFD ) ) {
		if (modelType != LINEARPERIODIC && baseFlow == "" ){
			cout << "ERROR: for linear or adjoint models, "
            "must specify a base flow" << endl;
			exit(1);
		}
		else if (modelType != LINEARPERIODIC && periodBaseFlowName != ""){
			cout << "WARNING: for linear or adjoint models, "
            "a periodic base flow is not needed" << endl;
			exit(1);
		}
		else if (modelType == LINEARPERIODIC && periodBaseFlowName == "" ) {
			cout << "ERROR: for linear periodic model, "
			"must specify a periodic base flow" << endl;
			exit(1);
		}
		else if (modelType == LINEARPERIODIC && baseFlow != "" ) {
			cout << "WARNING: for linear periodic model, "
            "a single baseflow is not needed" << endl;
			exit(1);
		}
    }

    // create output directory if not already present
    AddSlashToPath( outdir );
    mkdir( outdir.c_str(), S_IRWXU | S_IRWXG | S_IRWXO );

    // output command line arguments
    string cmd = parser.getParameters();
    cout << "Command:" << endl << cmd << "\n" << endl;
    parser.saveParameters( outdir + name + ".cmd" );

    // Name of this run
    cout << "Run name: " << name << "\n" << endl;

    // Setup grid
    cout << "Grid parameters:" << endl
        << "    nx      " << nx << endl
        << "    ny      " << ny << endl
        << "    ngrid   " << ngrid << endl
        << "    length  " << length << endl
        << "    xoffset " << xOffset << endl
		<< "    yoffset " << yOffset << endl
		<< "    xshift  " << xShift << endl
		<< "    yshift  " << yShift << endl
        << endl;
    Grid grid( nx, ny, ngrid, length, xOffset, yOffset );
	grid.setXShift( xShift );
	grid.setYShift( yShift );

    // Setup geometry
    Geometry geom;
    cout << "Reading geometry from file " << geomFile << endl;
    if ( geom.load( geomFile ) ) {
        cout << "    " << geom.getNumPoints() << " points on the boundary" << "\n" << endl;
    }
    else {
        exit(-1);
    }

    // Setup equations to solve
    cout << "Reynolds number = " << Reynolds << "\n" << endl;
    cout << "Setting up Immersed Boundary Solver..." << flush;
    double magnitude = 1;
    double alpha = 0;  // angle of background flow
    Flux q_potential = Flux::UniformFlow( grid, magnitude, alpha );

    NavierStokesModel* model = NULL;
    IBSolver* solver = NULL;
    SFDSolver* SFDsolver = NULL;
	State x00( grid, geom.getNumPoints() );

	switch (modelType){
		case NONLINEAR:
            model =  new NavierStokesModel( grid, geom, Reynolds, q_potential );
			solver = new NonlinearIBSolver( grid, *model, dt, schemeType );
			break;
		case LINEAR:
            if ( ! x00.load( baseFlow ) ) {
                cout << "baseflow failed to load.  Exiting program." << endl;
                exit(1);
            }
            model =  new NavierStokesModel( grid, geom, Reynolds );
			solver = new LinearizedIBSolver( grid, *model, dt, schemeType, x00 );
			break;
		case ADJOINT:
            if ( ! x00.load( baseFlow ) ) {
                cout << "baseflow failed to load.  Exiting program." << endl;
                exit(1);
            }
            model =  new NavierStokesModel( grid, geom, Reynolds );
			solver = new AdjointIBSolver( grid, *model, dt, schemeType, x00 );
			break;
		case LINEARPERIODIC:{
			// load periodic baseflow files
			vector<State> x0(period, x00);
			char pbffilename[256];
			string pbf = periodBaseFlowName;
			for (int i=0; i < period; i++) {
				//cout << "loading the " << i << "-th periodic baseflow:" << endl;
				sprintf(pbffilename, pbf.c_str(), i + periodStart);
				x0[i].load(pbffilename);
			}
			x00 = x0[0];
            model =  new NavierStokesModel( grid, geom, Reynolds );
			solver = new LinearizedPeriodicIBSolver( grid, *model, dt, schemeType, x0, period ) ;
			break;
			}
		case SFD:{
            cout << "SFD parameters:" << endl;
            cout << "    chi =   " << chi << endl;
            cout << "    Delta = " << Delta << endl << endl;
            model =  new NavierStokesModel( grid, geom, Reynolds, q_potential );
			SFDsolver = new SFDSolver( grid, *model, dt, schemeType, Delta, chi ) ;
            solver = SFDsolver;
			break;
			}
		case INVALID:
			cout << "ERROR: must specify a valid modelType" << endl;
			exit(1);
			break;
	}

	assert( model != NULL );
    assert( solver != NULL );
    if( modelType == SFD ) {
        assert( chi != 0 );
        assert( SFDsolver != null );
    }
    model->init();

    // Setup timestepper
    cout << "using " << solver->getName() << " timestepper" << endl;
    cout << "    dt = " << dt << "\n" << endl;
	if ( ! solver->load( outdir + name ) ) {
        // Set the tolerance for a ConjugateGradient solver below
        // Otherwise default is tol = 1e-7
        // solver->setTol( 1e-8 )
        solver->init();
        solver->save( outdir + name );
    }

    // Load initial condition
    State x( grid, geom.getNumPoints() );
    x.omega = 0.;
    x.f = 0.;
    x.q = 0.;
	if (icFile != "") {
	    cout << "Loading initial condition from file: " << icFile << endl;
        if ( ! x.load(icFile) ) {
            cout << "    (failed: using zero initial condition)" << endl;
        }
		if ( subtractBaseflow == true ) {
            cout << "    Subtracting initial condition by baseflow to form a linear initial perturbation" << endl;
			if (modelType != NONLINEAR) {
				assert((x.q).Ngrid() == (x00.q).Ngrid());
				assert((x.omega).Ngrid() == (x00.omega).Ngrid());
				x.q -= x00.q;
				x.omega -= x00.omega;
				x.f = 0;
			}
			else {
				cout << "Flag subbaseflow should be true only for linear cases"<< endl;
				exit(1);
			}
            if (resetTime == true) {
                x.timestep = 0;
                x.time = 0.;
            }
		}

        if ( modelType == SFD ) {
            SFDsolver->loadFilteredState( icFile );
        }

    }
    else {
        cout << "Using zero initial condition" << endl;
    }
    // Calculate flux for state, in case only vorticity was saved
    model->refreshState( x );

	cout << endl << "Initial timestep = " << x.timestep << "\n" << endl;

    // Setup output routines
    OutputTecplot tecplot( outdir + name + numDigitInFileName + ".plt", "Test run, step" +  numDigitInFileName);
    OutputRestart restart( outdir + name + numDigitInFileName + ".bin" );
    OutputForce force( outdir + name + ".force" );
    OutputEnergy energy( outdir + name + ".energy" );

    Logger logger;
    // Output Tecplot file every timestep
    if ( iTecplot > 0 ) {
        cout << "Writing Tecplot file every " << iTecplot << " step(s)" << endl;
        logger.addOutput( &tecplot, iTecplot );
    }
    if ( iRestart > 0 ) {
        cout << "Writing restart file every " << iRestart << " step(s)" << endl;
        logger.addOutput( &restart, iRestart );
    }
    if ( iForce > 0 ) {
        cout << "Writing forces every " << iForce << " step(s)" << endl;
        logger.addOutput( &force, iForce );
    }
    if ( iEnergy > 0 ) {
        cout << "Writing energy every " << iForce << " step(s)" << endl;
        logger.addOutput( &energy, iEnergy );
    }
    cout << endl;
    logger.init();
    logger.doOutput( x );

    cout << "Integrating for " << numSteps << " steps" << endl;
    for(int i=1; i <= numSteps; ++i) {
        cout << "\nstep " << i << endl;
        State xtemp( x ); // For SFD norm calculation

		solver->advance( x );
        double lift;
        double drag;
        x.computeNetForce( drag, lift );
        cout << "    x force: " << setw(16) << drag*2 << ", y force: "
            << setw(16) << lift*2 << "\n";
        logger.doOutput( x );

        // For SFD
        if( modelType == SFD ) {
            Scalar dx = xtemp.omega-x.omega;
            double twoNorm = sqrt(InnerProduct(dx, dx)) / dt;

            if ( (x.timestep % iRestart == 0 ) && (chi != 0.0) ) {
                SFDsolver->saveFilteredState( outdir, name, numDigitInFileName );
            }

            cout << "    ||dx||/dt = " << setw(13) << twoNorm << endl;
        }

    }
    logger.cleanup();

	delete solver;
    return 0;
}

ModelType str2model( string modelName ) {
    ModelType type;
    MakeLowercase( modelName );

    if ( modelName == "nonlinear" ) {
        type = NONLINEAR;
    }
    else if ( modelName == "linear" ) {
        type = LINEAR;
    }
    else if ( modelName == "adjoint" ) {
        type = ADJOINT;
    }
	else if ( modelName == "linearperiodic" ) {
        type = LINEARPERIODIC;
    }
	else if ( modelName == "sfd" ) {
		type = SFD;
	}
    else {
        cerr << "Unrecognized model: " << modelName << endl;
        type = INVALID;
    }
    return type;
}

Scheme::SchemeType str2scheme( string schemeName ) {
	Scheme::SchemeType type;
    MakeLowercase( schemeName );
    if ( schemeName == "euler" ) {
        type = Scheme::EULER;
    }
    else if ( schemeName == "ab2" ) {
        type = Scheme::AB2;
    }
    else if ( schemeName == "rk3" ) {
        type = Scheme::RK3;
    }
    else if ( schemeName == "rk3b" ) {
        type = Scheme::RK3b;
    }
    else {
        cerr << "Unrecognized integration scheme: " << schemeName;
		cerr << "    Exiting program." << endl;
        exit(1);
    }
    return type;
}

<|endoftext|>