<commit_before>/*
 * jcom.oscroute
 * External for Jamoma: parse and pass OpenSoundControl messages
 * By Tim Place, Copyright  2006
 *
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html
 */

#include "Jamoma.h"

#define MAX_ARGCOUNT 100
#define MAX_MESS_SIZE 2048

typedef struct _oscroute{					// Data Structure for this object
	t_object		ob;							// REQUIRED: Our object
	void			*obex;						// REQUIRED: Object Extensions used by Jitter/Attribute stuff
	void			*outlets[MAX_ARGCOUNT];		// my outlet array
	void			*outlet_overflow;			// this outlet doubles as the dumpout outlet
	t_symbol		*arguments[MAX_ARGCOUNT];	// symbols to match
	long unsigned	arglen[MAX_ARGCOUNT];		// strlen of symbols to match
	short			num_args;
	long			attr_strip;					// ATTRIBUTE: 1 = strip leading slash off any messages
	void			*proxy_inlet;				// pointer to the second inlet (when present)
} t_oscroute;

// Prototypes for our methods:
void *oscroute_new(t_symbol *s, long argc, t_atom *argv);
void oscroute_free(t_oscroute *x);
void oscroute_assist(t_oscroute *x, void *b, long msg, long arg, char *dst);
void oscroute_bang(t_oscroute *x);
void oscroute_int(t_oscroute *x, long n);
void oscroute_float(t_oscroute *x, double f);
void oscroute_list(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv);
void oscroute_symbol(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv);
//void oscroute_list(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv);

// Globals
t_class		*oscroute_class;				// Required: Global pointer for our class

/************************************************************************************/
// Main() Function

int main(void)				// main recieves a copy of the Max function macros table
{
	long attrflags = 0;
	t_class *c;
	t_object *attr;

	// Initialize Globals
	jamoma_init();

	// Define our class
	c = class_new("jcom.oscroute",(method)oscroute_new, (method)oscroute_free, (short)sizeof(t_oscroute), (method)0L, A_GIMME, 0);
	class_obexoffset_set(c, calcoffset(t_oscroute, obex));

	// Make methods accessible for our class:
	class_addmethod(c, (method)oscroute_bang,			"bang",		0L,			0L);
	class_addmethod(c, (method)oscroute_int,			"int",		A_DEFLONG,	0L);
	class_addmethod(c, (method)oscroute_float,			"float",	A_DEFFLOAT,	0L);
	class_addmethod(c, (method)oscroute_list,			"list",		A_GIMME,	0L);
  	class_addmethod(c, (method)oscroute_symbol,			"anything", A_GIMME,	0L);
	class_addmethod(c, (method)oscroute_assist,			"assist",	A_CANT,		0L);
    class_addmethod(c, (method)object_obex_dumpout, 	"dumpout",	A_CANT,		0);
    class_addmethod(c, (method)object_obex_quickref,	"quickref", A_CANT,		0);

	// ATTRIBUTE: strip
	attr = attr_offset_new("strip", _sym_long, attrflags,
		(method)0, (method)0, calcoffset(t_oscroute, attr_strip));
	class_addattr(c, attr);

	// Finalize our class
	class_register(CLASS_BOX, c);
	oscroute_class = c;
	return 0;
}

/************************************************************************************/
// Object Life

void *oscroute_new(t_symbol *s, long argc, t_atom *argv)
{
	short i;
	t_oscroute	*x = (t_oscroute *)object_alloc(oscroute_class);

	if(x){
		x->outlet_overflow = outlet_new(x, 0);		// overflow outlet
		//object_obex_store((void *)x, _sym_dumpout, (object *)x->outlet_overflow);	// dumpout
		x->num_args = argc;

		if(argc < 1){	// if no args are provided, we provide a way to set the arg using an inlet
			x->num_args = 1;
			x->arguments[0] = gensym("/nil");
			x->arglen[0] = 4;
			x->proxy_inlet = proxy_new(x, 1, 0L);
			x->outlets[0] = outlet_new(x, 0);
		}
		else{
			x->proxy_inlet = 0;
			for(i=x->num_args-1; i >= 0; i--){
				x->outlets[i] = outlet_new(x, 0);		// Create Outlet
				switch(argv[i].a_type){
					case A_SYM:
						//atom_setsym(&(x->arguments[i]), atom_getsym(argv+i));
						x->arguments[i] = atom_getsym(argv+i);
						x->arglen[i] = strlen(atom_getsym(argv+i)->s_name);
						break;
					default:
						error("jcom.oscroute - invalid arguments - all args must be symbols");
				}
			}
		}
		//attr_args_process(x, argc, argv);			//handle attribute args
	}
	return (x);										// return the pointer to our new instantiation
}

void oscroute_free(t_oscroute *x)
{
	if(x->proxy_inlet != 0)
		freeobject((t_object *)(x->proxy_inlet));
}

/************************************************************************************/
// Methods bound to input/inlets

// Method for Assistance Messages
void oscroute_assist(t_oscroute *x, void *b, long msg, long arg, char *dst)
{
	if(msg==1) 						// Inlet
		strcpy(dst, "Input");
	else if(msg==2){ 				// Outlets
		if(arg < x->num_args)
			strcpy(dst, x->arguments[arg]->s_name);
		else
			strcpy(dst, "dumpout / overflow from non-matching input");
 	}
}

// BANG INPUT: STRAIGHT TO OVERFLOW
void oscroute_bang(t_oscroute *x)
{
	outlet_bang(x->outlet_overflow);
}

// INT INPUT: STRAIGHT TO OVERFLOW
void oscroute_int(t_oscroute *x, long n)
{
	outlet_int(x->outlet_overflow, n);
}

// FLOAT INPUT: STRAIGHT TO OVERFLOW
void oscroute_float(t_oscroute *x, double f)
{
	outlet_float(x->outlet_overflow, f);
}

// LIST INPUT: STRAIGHT TO OVERFLOW
void oscroute_list(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv)
{
	outlet_list(x->outlet_overflow, _sym_list, argc , argv);
}

char* matchesWildcard(const char *msg, const char *arg, unsigned long len)
{
	if(strncmp(msg, arg, len) == 0)
		return strstr((char*)msg, "/");

	return NULL;
}

inline int wildCardOffset(unsigned int numberOfWc)
{
	return 2 * numberOfWc;
}

// SYMBOL INPUT
void oscroute_symbol(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv)
{
	short		i;
	t_symbol	*message;				// our input message to match
	t_symbol	*output;
	char		input[MAX_MESS_SIZE];	// our input string
	long		inlet = proxy_getinlet((t_object *)x);

	// If the message comes in the second inlet, then set the string to match...
	if(inlet == 1){
		x->arguments[0] = msg;
		x->arglen[0] = strlen(msg->s_name);
		return;
	}

	// Otherwise match the stored string(s) and output...
	strcpy(input, msg->s_name);

	// Make sure we are dealing with valid OSC input by looking for a leading slash

	if(input[0] != '/') {
		outlet_anything(x->outlet_overflow, msg, argc , argv);
		return;
	}

	message = gensym(input);

	char *wc, *c;
	int wcCount = 0;  // wild card count
	bool overFlow = true;
	for (i=0; i < x->num_args; i++) {
		// Look for exact matches first.
		if (strncmp(msg->s_name, x->arguments[i]->s_name, x->arglen[i])==0) {
			// If incoming message is longer than argument...
			if (strlen(msg->s_name) > x->arglen[i]){
				// ...it is only a match if it continues with a slash
				if (input[x->arglen[i]] == '/') {
					output = gensym(msg->s_name + x->arglen[i]);
					outlet_anything(x->outlets[i], output, argc , argv);
					overFlow = false;
					break;
				}
			}
			// If the incoming message is no longer we know that we have a match
			else {

				// We then have to check what message to return.
				// The message received has no arguments:
				if (argc == 0) {
					outlet_bang(x->outlets[i]);
					overFlow = false;
					break;
				}
				// The message received has one argument only:
				else if (argc==1) {
					overFlow = false;
					// int argument
					if (argv->a_type==A_LONG) {
						outlet_int(x->outlets[i],argv->a_w.w_long);
						break;
					}
					// float argument
					else if (argv->a_type==A_FLOAT) {
						outlet_float(x->outlets[i],argv->a_w.w_float);
						break;
					}
					// something else
					else if (argv->a_type==A_SYM) {
						outlet_anything(x->outlets[i],argv->a_w.w_sym,0,0);
						break;
					}
				}
				// There are two or more arguments: check if first is A_SYM
				else {
					if (argv->a_type==A_SYM) {
						output = argv->a_w.w_sym;
						argc--;
						argv++;
					}
					else
						output = _sym_list;
					outlet_anything(x->outlets[i], output, argc , argv);
					overFlow = false;
					break;
				}
			}
		}
	}
	// If no exact matches, look for wildcards.
	for (i=0; i < x->num_args; i++) {
		// Check to see if this argument has a wildcard
		if(wc = strstr(x->arguments[i]->s_name, "/*")) {
			if(*(wc+2) == '\0') {
				// Wildcard follows parameter names, i.e. /fifth/moon/of/aragon/*
				if(c = matchesWildcard(msg->s_name, x->arguments[i]->s_name, x->arglen[i] - 1)) {
					// Need to strip off preceeding part of message
					outlet_anything(x->outlets[i], gensym(strstr(c+1, "/")), argc, argv);
					return;
				} else {
					// We break here because if the strncmp() fails it means we have a wildcard following an
					// OSC message i.e. /robot/* but the incoming message doesn't begin with /robot
			//		break;
				}
			} else {

				while(wc && *(wc + 2) == '/') {
					wcCount++;
					// Skip to next potential wildcard
					wc += 2;
					wc = strstr(wc, "/*");
				}
				c = msg->s_name + 1;
				for(int skipCnt = 0; skipCnt < wcCount; ++skipCnt) {
					c = strstr(c + 1, "/");
				}

				if(c = matchesWildcard(c, x->arguments[i]->s_name + wildCardOffset(wcCount), strlen(c))) {
					outlet_anything(x->outlets[i], gensym(c), argc, argv);
					return;
				} else {
					wcCount = 0;
				}
			}
		}
	}

	// the message was never reckognised
	if(overFlow)
		outlet_anything(x->outlet_overflow, msg, argc , argv);
}<commit_msg>no longer crashes as per bug #1854416 reported by Pascal<commit_after>/*
 * jcom.oscroute
 * External for Jamoma: parse and pass OpenSoundControl messages
 * By Tim Place, Copyright  2006
 *
 * License: This code is licensed under the terms of the GNU LGPL
 * http://www.gnu.org/licenses/lgpl.html
 */

#include "Jamoma.h"

#define MAX_ARGCOUNT 100
#define MAX_MESS_SIZE 2048

typedef struct _oscroute{					// Data Structure for this object
	t_object		ob;							// REQUIRED: Our object
	void			*obex;						// REQUIRED: Object Extensions used by Jitter/Attribute stuff
	void			*outlets[MAX_ARGCOUNT];		// my outlet array
	void			*outlet_overflow;			// this outlet doubles as the dumpout outlet
	t_symbol		*arguments[MAX_ARGCOUNT];	// symbols to match
	long unsigned	arglen[MAX_ARGCOUNT];		// strlen of symbols to match
	short			num_args;
	long			attr_strip;					// ATTRIBUTE: 1 = strip leading slash off any messages
	void			*proxy_inlet;				// pointer to the second inlet (when present)
} t_oscroute;

// Prototypes for our methods:
void *oscroute_new(t_symbol *s, long argc, t_atom *argv);
void oscroute_free(t_oscroute *x);
void oscroute_assist(t_oscroute *x, void *b, long msg, long arg, char *dst);
void oscroute_bang(t_oscroute *x);
void oscroute_int(t_oscroute *x, long n);
void oscroute_float(t_oscroute *x, double f);
void oscroute_list(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv);
void oscroute_symbol(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv);
//void oscroute_list(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv);

// Globals
t_class		*oscroute_class;				// Required: Global pointer for our class

/************************************************************************************/
// Main() Function

int main(void)				// main recieves a copy of the Max function macros table
{
	long attrflags = 0;
	t_class *c;
	t_object *attr;

	// Initialize Globals
	jamoma_init();

	// Define our class
	c = class_new("jcom.oscroute",(method)oscroute_new, (method)oscroute_free, (short)sizeof(t_oscroute), (method)0L, A_GIMME, 0);
	class_obexoffset_set(c, calcoffset(t_oscroute, obex));

	// Make methods accessible for our class:
	class_addmethod(c, (method)oscroute_bang,			"bang",		0L,			0L);
	class_addmethod(c, (method)oscroute_int,			"int",		A_DEFLONG,	0L);
	class_addmethod(c, (method)oscroute_float,			"float",	A_DEFFLOAT,	0L);
	class_addmethod(c, (method)oscroute_list,			"list",		A_GIMME,	0L);
  	class_addmethod(c, (method)oscroute_symbol,			"anything", A_GIMME,	0L);
	class_addmethod(c, (method)oscroute_assist,			"assist",	A_CANT,		0L);
    class_addmethod(c, (method)object_obex_dumpout, 	"dumpout",	A_CANT,		0);
    class_addmethod(c, (method)object_obex_quickref,	"quickref", A_CANT,		0);

	// ATTRIBUTE: strip
	attr = attr_offset_new("strip", _sym_long, attrflags,
		(method)0, (method)0, calcoffset(t_oscroute, attr_strip));
	class_addattr(c, attr);

	// Finalize our class
	class_register(CLASS_BOX, c);
	oscroute_class = c;
	return 0;
}

/************************************************************************************/
// Object Life

void *oscroute_new(t_symbol *s, long argc, t_atom *argv)
{
	short i;
	t_oscroute	*x = (t_oscroute *)object_alloc(oscroute_class);

	if(x){
		x->outlet_overflow = outlet_new(x, 0);		// overflow outlet
		//object_obex_store((void *)x, _sym_dumpout, (object *)x->outlet_overflow);	// dumpout
		x->num_args = argc;

		if(argc < 1){	// if no args are provided, we provide a way to set the arg using an inlet
			x->num_args = 1;
			x->arguments[0] = gensym("/nil");
			x->arglen[0] = 4;
			x->proxy_inlet = proxy_new(x, 1, 0L);
			x->outlets[0] = outlet_new(x, 0);
		}
		else{
			x->proxy_inlet = 0;
			for(i=x->num_args-1; i >= 0; i--){
				x->outlets[i] = outlet_new(x, 0);		// Create Outlet
				switch(argv[i].a_type){
					case A_SYM:
						//atom_setsym(&(x->arguments[i]), atom_getsym(argv+i));
						x->arguments[i] = atom_getsym(argv+i);
						x->arglen[i] = strlen(atom_getsym(argv+i)->s_name);
						break;
					default:
						error("jcom.oscroute - invalid arguments - all args must be symbols");
				}
			}
		}
		//attr_args_process(x, argc, argv);			//handle attribute args
	}
	return (x);										// return the pointer to our new instantiation
}

void oscroute_free(t_oscroute *x)
{
	if(x->proxy_inlet != 0)
		freeobject((t_object *)(x->proxy_inlet));
}

/************************************************************************************/
// Methods bound to input/inlets

// Method for Assistance Messages
void oscroute_assist(t_oscroute *x, void *b, long msg, long arg, char *dst)
{
	if(msg==1) 						// Inlet
		strcpy(dst, "Input");
	else if(msg==2){ 				// Outlets
		if(arg < x->num_args)
			strcpy(dst, x->arguments[arg]->s_name);
		else
			strcpy(dst, "dumpout / overflow from non-matching input");
 	}
}

// BANG INPUT: STRAIGHT TO OVERFLOW
void oscroute_bang(t_oscroute *x)
{
	outlet_bang(x->outlet_overflow);
}

// INT INPUT: STRAIGHT TO OVERFLOW
void oscroute_int(t_oscroute *x, long n)
{
	outlet_int(x->outlet_overflow, n);
}

// FLOAT INPUT: STRAIGHT TO OVERFLOW
void oscroute_float(t_oscroute *x, double f)
{
	outlet_float(x->outlet_overflow, f);
}

// LIST INPUT: STRAIGHT TO OVERFLOW
void oscroute_list(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv)
{
	outlet_list(x->outlet_overflow, _sym_list, argc , argv);
}

char* matchesWildcard(const char *msg, const char *arg, unsigned long len)
{
	if(strncmp(msg, arg, len) == 0)
		return strstr((char*)msg, "/");

	return NULL;
}

inline int wildCardOffset(unsigned int numberOfWc)
{
	return 2 * numberOfWc;
}

// SYMBOL INPUT
void oscroute_symbol(t_oscroute *x, t_symbol *msg, long argc, t_atom *argv)
{
	short		i;
	t_symbol	*message;				// our input message to match
	t_symbol	*output;
	char		input[MAX_MESS_SIZE];	// our input string
	long		inlet = proxy_getinlet((t_object *)x);

	// If the message comes in the second inlet, then set the string to match...
	if(inlet == 1){
		x->arguments[0] = msg;
		x->arglen[0] = strlen(msg->s_name);
		return;
	}

	// Otherwise match the stored string(s) and output...
	strcpy(input, msg->s_name);

	// Make sure we are dealing with valid OSC input by looking for a leading slash

	if(input[0] != '/') {
		outlet_anything(x->outlet_overflow, msg, argc , argv);
		return;
	}

	message = gensym(input);

	char *wc, *c;
	int wcCount = 0;  // wild card count
	bool overFlow = true;
	for (i=0; i < x->num_args; i++) {
		// Look for exact matches first.
		if (strncmp(msg->s_name, x->arguments[i]->s_name, x->arglen[i])==0) {
			// If incoming message is longer than argument...
			if (strlen(msg->s_name) > x->arglen[i]){
				// ...it is only a match if it continues with a slash
				if (input[x->arglen[i]] == '/') {
					output = gensym(msg->s_name + x->arglen[i]);
					outlet_anything(x->outlets[i], output, argc , argv);
					overFlow = false;
					break;
				}
			}
			// If the incoming message is no longer we know that we have a match
			else {

				// We then have to check what message to return.
				// The message received has no arguments:
				if (argc == 0) {
					outlet_bang(x->outlets[i]);
					overFlow = false;
					break;
				}
				// The message received has one argument only:
				else if (argc==1) {
					overFlow = false;
					// int argument
					if (argv->a_type==A_LONG) {
						outlet_int(x->outlets[i],argv->a_w.w_long);
						break;
					}
					// float argument
					else if (argv->a_type==A_FLOAT) {
						outlet_float(x->outlets[i],argv->a_w.w_float);
						break;
					}
					// something else
					else if (argv->a_type==A_SYM) {
						outlet_anything(x->outlets[i],argv->a_w.w_sym,0,0);
						break;
					}
				}
				// There are two or more arguments: check if first is A_SYM
				else {
					if (argv->a_type==A_SYM) {
						output = argv->a_w.w_sym;
						argc--;
						argv++;
					}
					else
						output = _sym_list;
					outlet_anything(x->outlets[i], output, argc , argv);
					overFlow = false;
					break;
				}
			}
		}
	}
	// If no exact matches, look for wildcards.
	for (i=0; i < x->num_args; i++) {
		// Check to see if this argument has a wildcard
		if(wc = strstr(x->arguments[i]->s_name, "/*")) {
			if(*(wc+2) == '\0') {
				// Wildcard follows parameter names, i.e. /fifth/moon/of/aragon/*
				if(c = matchesWildcard(msg->s_name, x->arguments[i]->s_name, x->arglen[i] - 1)) {
					// Need to strip off preceeding part of message
					char *temp = strstr(c+1, "/");
					if(temp)
						outlet_anything(x->outlets[i], gensym(temp), argc, argv);
					return;
				} else {
					// We break here because if the strncmp() fails it means we have a wildcard following an
					// OSC message i.e. /robot/* but the incoming message doesn't begin with /robot
			//		break;
				}
			} else {

				while(wc && *(wc + 2) == '/') {
					wcCount++;
					// Skip to next potential wildcard
					wc += 2;
					wc = strstr(wc, "/*");
				}
				c = msg->s_name + 1;
				for(int skipCnt = 0; skipCnt < wcCount; ++skipCnt) {
					c = strstr(c + 1, "/");
				}

				if(c = matchesWildcard(c, x->arguments[i]->s_name + wildCardOffset(wcCount), strlen(c))) {
					outlet_anything(x->outlets[i], gensym(c), argc, argv);
					return;
				} else {
					wcCount = 0;
				}
			}
		}
	}

	// the message was never reckognised
	if(overFlow)
		outlet_anything(x->outlet_overflow, msg, argc , argv);
}<|endoftext|>


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

#include <votca/tools/version.h>
#include <iostream>
#include "version.h"
#include "config.h"

namespace gmx {
#ifndef GMX4DEV
    extern "C"
    {
#endif
        #include <copyrite.h>
#ifndef GMX4DEV
    }
#endif
    // this one is needed because of bool is defined in one of the headers included by gmx
    #undef bool
}
namespace votca { namespace csg {

#ifdef HGVERSION
  static const std::string version_str = VERSION " " HGVERSION " (compiled " __DATE__ ", " __TIME__ ")";
#else
  static const std::string version_str = VERSION "(compiled " __DATE__ ", " __TIME__ ")";
#endif

const std::string &CsgVersionStr()
{
    return version_str;
}

void HelpTextHeader(const std::string &tool_name)
{
    std::cout
         << "==================================================\n"
         << "========   VOTCA (http://www.votca.org)   ========\n"
         << "==================================================\n\n"
	 << "please submit bugs to " PACKAGE_BUGREPORT "\n\n"
	 << tool_name << ", version " << votca::csg::CsgVersionStr()
         << "\nvotca_tools, version " << votca::tools::ToolsVersionStr()
         << "\ngromacs, " << gmx::GromacsVersion()
         << "\n\n";
}

}}

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

#include <votca/tools/version.h>
#include <iostream>
#include "version.h"
#include "config.h"

#ifndef GMX4DEV
    extern "C"
    {
#endif
        #include <copyrite.h>
#ifndef GMX4DEV
    }
#endif
    // this one is needed because of bool is defined in one of the headers included by gmx
    #undef bool

namespace votca { namespace csg {

#ifdef HGVERSION
  static const std::string version_str = VERSION " " HGVERSION " (compiled " __DATE__ ", " __TIME__ ")";
#else
  static const std::string version_str = VERSION "(compiled " __DATE__ ", " __TIME__ ")";
#endif

const std::string &CsgVersionStr()
{
    return version_str;
}

void HelpTextHeader(const std::string &tool_name)
{
    std::cout
         << "==================================================\n"
         << "========   VOTCA (http://www.votca.org)   ========\n"
         << "==================================================\n\n"
	 << "please submit bugs to " PACKAGE_BUGREPORT "\n\n"
	 << tool_name << ", version " << votca::csg::CsgVersionStr()
         << "\nvotca_tools, version " << votca::tools::ToolsVersionStr()
         << "\ngromacs, " << GromacsVersion()
         << "\n\n";
}

}}

<|endoftext|>


<commit_before>#include "globals.hh"
#include "shared.hh"
#include "store-api.hh"
#include "util.hh"

#include <algorithm>
#include <cctype>
#include <exception>
#include <iostream>
#include <mutex>

#include <cstdlib>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>

#include <openssl/crypto.h>

namespace nix {

static bool gcWarning = true;

void printGCWarning()
{
    if (!gcWarning) return;
    static bool haveWarned = false;
    warnOnce(haveWarned,
        "you did not specify '--add-root'; "
        "the result might be removed by the garbage collector");
}

void printMissing(ref<Store> store, const PathSet & paths, Verbosity lvl)
{
    unsigned long long downloadSize, narSize;
    PathSet willBuild, willSubstitute, unknown;
    store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
    printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl);
}

void printMissing(ref<Store> store, const PathSet & willBuild,
    const PathSet & willSubstitute, const PathSet & unknown,
    unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl)
{
    if (!willBuild.empty()) {
        printMsg(lvl, "these derivations will be built:");
        Paths sorted = store->topoSortPaths(willBuild);
        reverse(sorted.begin(), sorted.end());
        for (auto & i : sorted)
            printMsg(lvl, fmt("  %s", i));
    }

    if (!willSubstitute.empty()) {
        printMsg(lvl, fmt("these paths will be fetched (%.2f MiB download, %.2f MiB unpacked):",
                downloadSize / (1024.0 * 1024.0),
                narSize / (1024.0 * 1024.0)));
        for (auto & i : willSubstitute)
            printMsg(lvl, fmt("  %s", i));
    }

    if (!unknown.empty()) {
        printMsg(lvl, fmt("don't know how to build these paths%s:",
                (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")));
        for (auto & i : unknown)
            printMsg(lvl, fmt("  %s", i));
    }
}

string getArg(const string & opt,
    Strings::iterator & i, const Strings::iterator & end)
{
    ++i;
    if (i == end) throw UsageError(format("'%1%' requires an argument") % opt);
    return *i;
}

/* OpenSSL is not thread-safe by default - it will randomly crash
   unless the user supplies a mutex locking function. So let's do
   that. */
static std::vector<std::mutex> opensslLocks;

static void opensslLockCallback(int mode, int type, const char * file, int line)
{
    if (mode & CRYPTO_LOCK)
        opensslLocks[type].lock();
    else
        opensslLocks[type].unlock();
}

static void sigHandler(int signo) { }

void initNix()
{
    /* Turn on buffering for cerr. */
#if HAVE_PUBSETBUF
    static char buf[1024];
    std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
#endif

    /* Initialise OpenSSL locking. */
    opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
    CRYPTO_set_locking_callback(opensslLockCallback);

    settings.loadConfFile();

    startSignalHandlerThread();

    /* Reset SIGCHLD to its default. */
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_handler = SIG_DFL;
    act.sa_flags = 0;
    if (sigaction(SIGCHLD, &act, 0))
        throw SysError("resetting SIGCHLD");

    /* Install a dummy SIGUSR1 handler for use with pthread_kill(). */
    act.sa_handler = sigHandler;
    if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1");

    /* Register a SIGSEGV handler to detect stack overflows. */
    detectStackOverflow();

    /* There is no privacy in the Nix system ;-)  At least not for
       now.  In particular, store objects should be readable by
       everybody. */
    umask(0022);

    /* Initialise the PRNG. */
    struct timeval tv;
    gettimeofday(&tv, 0);
    srandom(tv.tv_usec);

    /* On macOS, don't use the per-session TMPDIR (as set e.g. by
       sshd). This breaks build users because they don't have access
       to the TMPDIR, in particular in ‘nix-store --serve’. */
#if __APPLE__
    if (getuid() == 0 && hasPrefix(getEnv("TMPDIR"), "/var/folders/"))
        unsetenv("TMPDIR");
#endif
}

LegacyArgs::LegacyArgs(const std::string & programName,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
    : MixCommonArgs(programName), parseArg(parseArg)
{
    mkFlag()
        .longName("no-build-output")
        .shortName('Q')
        .description("do not show build output")
        .set(&settings.verboseBuild, false);

    mkFlag()
        .longName("keep-failed")
        .shortName('K')
        .description("keep temporary directories of failed builds")
        .set(&(bool&) settings.keepFailed, true);

    mkFlag()
        .longName("keep-going")
        .shortName('k')
        .description("keep going after a build fails")
        .set(&(bool&) settings.keepGoing, true);

    mkFlag()
        .longName("fallback")
        .description("build from source if substitution fails")
        .set(&(bool&) settings.tryFallback, true);

    mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) {
        settings.set("max-jobs", s);
    });

    auto intSettingAlias = [&](char shortName, const std::string & longName,
        const std::string & description, const std::string & dest) {
        mkFlag<unsigned int>(shortName, longName, description, [=](unsigned int n) {
            settings.set(dest, std::to_string(n));
        });
    };

    intSettingAlias(0, "cores", "maximum number of CPU cores to use inside a build", "cores");
    intSettingAlias(0, "max-silent-time", "number of seconds of silence before a build is killed", "max-silent-time");
    intSettingAlias(0, "timeout", "number of seconds before a build is killed", "timeout");

    mkFlag(0, "readonly-mode", "do not write to the Nix store",
        &settings.readOnlyMode);

    mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'",
        &gcWarning, false);

    mkFlag()
        .longName("store")
        .label("store-uri")
        .description("URI of the Nix store to use")
        .dest(&(std::string&) settings.storeUri);
}

bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end)
{
    if (MixCommonArgs::processFlag(pos, end)) return true;
    bool res = parseArg(pos, end);
    if (res) ++pos;
    return res;
}

bool LegacyArgs::processArgs(const Strings & args, bool finish)
{
    if (args.empty()) return true;
    assert(args.size() == 1);
    Strings ss(args);
    auto pos = ss.begin();
    if (!parseArg(pos, ss.end()))
        throw UsageError(format("unexpected argument '%1%'") % args.front());
    return true;
}

void parseCmdLine(int argc, char * * argv,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    parseCmdLine(baseNameOf(argv[0]), argvToStrings(argc, argv), parseArg);
}

void parseCmdLine(const string & programName, const Strings & args,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    LegacyArgs(programName, parseArg).parseCmdline(args);
}

void printVersion(const string & programName)
{
    std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
    if (verbosity > lvlInfo) {
        Strings cfg;
#if HAVE_BOEHMGC
        cfg.push_back("gc");
#endif
#if HAVE_SODIUM
        cfg.push_back("signed-caches");
#endif
        std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n";
        std::cout << "Configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
        std::cout << "Store directory: " << settings.nixStore << "\n";
        std::cout << "State directory: " << settings.nixStateDir << "\n";
    }
    throw Exit();
}

void showManPage(const string & name)
{
    restoreSignals();
    setenv("MANPATH", settings.nixManDir.c_str(), 1);
    execlp("man", "man", name.c_str(), NULL);
    throw SysError(format("command 'man %1%' failed") % name.c_str());
}

int handleExceptions(const string & programName, std::function<void()> fun)
{
    ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this

    string error = ANSI_RED "error:" ANSI_NORMAL " ";
    try {
        try {
            fun();
        } catch (...) {
            /* Subtle: we have to make sure that any `interrupted'
               condition is discharged before we reach printMsg()
               below, since otherwise it will throw an (uncaught)
               exception. */
            setInterruptThrown();
            throw;
        }
    } catch (Exit & e) {
        return e.status;
    } catch (UsageError & e) {
        printError(
            format(error + "%1%\nTry '%2% --help' for more information.")
            % e.what() % programName);
        return 1;
    } catch (BaseError & e) {
        printError(format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
        if (e.prefix() != "" && !settings.showTrace)
            printError("(use '--show-trace' to show detailed location information)");
        return e.status;
    } catch (std::bad_alloc & e) {
        printError(error + "out of memory");
        return 1;
    } catch (std::exception & e) {
        printError(error + e.what());
        return 1;
    }

    return 0;
}

RunPager::RunPager()
{
    if (!isatty(STDOUT_FILENO)) return;
    char * pager = getenv("NIX_PAGER");
    if (!pager) pager = getenv("PAGER");
    if (pager && ((string) pager == "" || (string) pager == "cat")) return;

    Pipe toPager;
    toPager.create();

    pid = startProcess([&]() {
        if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
            throw SysError("dupping stdin");
        if (!getenv("LESS"))
            setenv("LESS", "FRSXMK", 1);
        restoreSignals();
        if (pager)
            execl("/bin/sh", "sh", "-c", pager, NULL);
        execlp("pager", "pager", NULL);
        execlp("less", "less", NULL);
        execlp("more", "more", NULL);
        throw SysError(format("executing '%1%'") % pager);
    });

    pid.setKillSignal(SIGINT);

    if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
        throw SysError("dupping stdout");
}

RunPager::~RunPager()
{
    try {
        if (pid != -1) {
            std::cout.flush();
            close(STDOUT_FILENO);
            pid.wait();
        }
    } catch (...) {
        ignoreException();
    }
}

string showBytes(unsigned long long bytes)
{
    return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
}

PrintFreed::~PrintFreed()
{
    if (show)
        std::cout << format("%1% store paths deleted, %2% freed\n")
            % results.paths.size()
            % showBytes(results.bytesFreed);
}

Exit::~Exit() { }

}
<commit_msg>execl: cast NULL sentinel to (char *), per man page and compiler warning<commit_after>#include "globals.hh"
#include "shared.hh"
#include "store-api.hh"
#include "util.hh"

#include <algorithm>
#include <cctype>
#include <exception>
#include <iostream>
#include <mutex>

#include <cstdlib>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>

#include <openssl/crypto.h>

namespace nix {

static bool gcWarning = true;

void printGCWarning()
{
    if (!gcWarning) return;
    static bool haveWarned = false;
    warnOnce(haveWarned,
        "you did not specify '--add-root'; "
        "the result might be removed by the garbage collector");
}

void printMissing(ref<Store> store, const PathSet & paths, Verbosity lvl)
{
    unsigned long long downloadSize, narSize;
    PathSet willBuild, willSubstitute, unknown;
    store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
    printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl);
}

void printMissing(ref<Store> store, const PathSet & willBuild,
    const PathSet & willSubstitute, const PathSet & unknown,
    unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl)
{
    if (!willBuild.empty()) {
        printMsg(lvl, "these derivations will be built:");
        Paths sorted = store->topoSortPaths(willBuild);
        reverse(sorted.begin(), sorted.end());
        for (auto & i : sorted)
            printMsg(lvl, fmt("  %s", i));
    }

    if (!willSubstitute.empty()) {
        printMsg(lvl, fmt("these paths will be fetched (%.2f MiB download, %.2f MiB unpacked):",
                downloadSize / (1024.0 * 1024.0),
                narSize / (1024.0 * 1024.0)));
        for (auto & i : willSubstitute)
            printMsg(lvl, fmt("  %s", i));
    }

    if (!unknown.empty()) {
        printMsg(lvl, fmt("don't know how to build these paths%s:",
                (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")));
        for (auto & i : unknown)
            printMsg(lvl, fmt("  %s", i));
    }
}

string getArg(const string & opt,
    Strings::iterator & i, const Strings::iterator & end)
{
    ++i;
    if (i == end) throw UsageError(format("'%1%' requires an argument") % opt);
    return *i;
}

/* OpenSSL is not thread-safe by default - it will randomly crash
   unless the user supplies a mutex locking function. So let's do
   that. */
static std::vector<std::mutex> opensslLocks;

static void opensslLockCallback(int mode, int type, const char * file, int line)
{
    if (mode & CRYPTO_LOCK)
        opensslLocks[type].lock();
    else
        opensslLocks[type].unlock();
}

static void sigHandler(int signo) { }

void initNix()
{
    /* Turn on buffering for cerr. */
#if HAVE_PUBSETBUF
    static char buf[1024];
    std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
#endif

    /* Initialise OpenSSL locking. */
    opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
    CRYPTO_set_locking_callback(opensslLockCallback);

    settings.loadConfFile();

    startSignalHandlerThread();

    /* Reset SIGCHLD to its default. */
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_handler = SIG_DFL;
    act.sa_flags = 0;
    if (sigaction(SIGCHLD, &act, 0))
        throw SysError("resetting SIGCHLD");

    /* Install a dummy SIGUSR1 handler for use with pthread_kill(). */
    act.sa_handler = sigHandler;
    if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1");

    /* Register a SIGSEGV handler to detect stack overflows. */
    detectStackOverflow();

    /* There is no privacy in the Nix system ;-)  At least not for
       now.  In particular, store objects should be readable by
       everybody. */
    umask(0022);

    /* Initialise the PRNG. */
    struct timeval tv;
    gettimeofday(&tv, 0);
    srandom(tv.tv_usec);

    /* On macOS, don't use the per-session TMPDIR (as set e.g. by
       sshd). This breaks build users because they don't have access
       to the TMPDIR, in particular in ‘nix-store --serve’. */
#if __APPLE__
    if (getuid() == 0 && hasPrefix(getEnv("TMPDIR"), "/var/folders/"))
        unsetenv("TMPDIR");
#endif
}

LegacyArgs::LegacyArgs(const std::string & programName,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
    : MixCommonArgs(programName), parseArg(parseArg)
{
    mkFlag()
        .longName("no-build-output")
        .shortName('Q')
        .description("do not show build output")
        .set(&settings.verboseBuild, false);

    mkFlag()
        .longName("keep-failed")
        .shortName('K')
        .description("keep temporary directories of failed builds")
        .set(&(bool&) settings.keepFailed, true);

    mkFlag()
        .longName("keep-going")
        .shortName('k')
        .description("keep going after a build fails")
        .set(&(bool&) settings.keepGoing, true);

    mkFlag()
        .longName("fallback")
        .description("build from source if substitution fails")
        .set(&(bool&) settings.tryFallback, true);

    mkFlag1('j', "max-jobs", "jobs", "maximum number of parallel builds", [=](std::string s) {
        settings.set("max-jobs", s);
    });

    auto intSettingAlias = [&](char shortName, const std::string & longName,
        const std::string & description, const std::string & dest) {
        mkFlag<unsigned int>(shortName, longName, description, [=](unsigned int n) {
            settings.set(dest, std::to_string(n));
        });
    };

    intSettingAlias(0, "cores", "maximum number of CPU cores to use inside a build", "cores");
    intSettingAlias(0, "max-silent-time", "number of seconds of silence before a build is killed", "max-silent-time");
    intSettingAlias(0, "timeout", "number of seconds before a build is killed", "timeout");

    mkFlag(0, "readonly-mode", "do not write to the Nix store",
        &settings.readOnlyMode);

    mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'",
        &gcWarning, false);

    mkFlag()
        .longName("store")
        .label("store-uri")
        .description("URI of the Nix store to use")
        .dest(&(std::string&) settings.storeUri);
}

bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end)
{
    if (MixCommonArgs::processFlag(pos, end)) return true;
    bool res = parseArg(pos, end);
    if (res) ++pos;
    return res;
}

bool LegacyArgs::processArgs(const Strings & args, bool finish)
{
    if (args.empty()) return true;
    assert(args.size() == 1);
    Strings ss(args);
    auto pos = ss.begin();
    if (!parseArg(pos, ss.end()))
        throw UsageError(format("unexpected argument '%1%'") % args.front());
    return true;
}

void parseCmdLine(int argc, char * * argv,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    parseCmdLine(baseNameOf(argv[0]), argvToStrings(argc, argv), parseArg);
}

void parseCmdLine(const string & programName, const Strings & args,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    LegacyArgs(programName, parseArg).parseCmdline(args);
}

void printVersion(const string & programName)
{
    std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
    if (verbosity > lvlInfo) {
        Strings cfg;
#if HAVE_BOEHMGC
        cfg.push_back("gc");
#endif
#if HAVE_SODIUM
        cfg.push_back("signed-caches");
#endif
        std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n";
        std::cout << "Configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
        std::cout << "Store directory: " << settings.nixStore << "\n";
        std::cout << "State directory: " << settings.nixStateDir << "\n";
    }
    throw Exit();
}

void showManPage(const string & name)
{
    restoreSignals();
    setenv("MANPATH", settings.nixManDir.c_str(), 1);
    execlp("man", "man", name.c_str(), (char *)NULL);
    throw SysError(format("command 'man %1%' failed") % name.c_str());
}

int handleExceptions(const string & programName, std::function<void()> fun)
{
    ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this

    string error = ANSI_RED "error:" ANSI_NORMAL " ";
    try {
        try {
            fun();
        } catch (...) {
            /* Subtle: we have to make sure that any `interrupted'
               condition is discharged before we reach printMsg()
               below, since otherwise it will throw an (uncaught)
               exception. */
            setInterruptThrown();
            throw;
        }
    } catch (Exit & e) {
        return e.status;
    } catch (UsageError & e) {
        printError(
            format(error + "%1%\nTry '%2% --help' for more information.")
            % e.what() % programName);
        return 1;
    } catch (BaseError & e) {
        printError(format(error + "%1%%2%") % (settings.showTrace ? e.prefix() : "") % e.msg());
        if (e.prefix() != "" && !settings.showTrace)
            printError("(use '--show-trace' to show detailed location information)");
        return e.status;
    } catch (std::bad_alloc & e) {
        printError(error + "out of memory");
        return 1;
    } catch (std::exception & e) {
        printError(error + e.what());
        return 1;
    }

    return 0;
}

RunPager::RunPager()
{
    if (!isatty(STDOUT_FILENO)) return;
    char * pager = getenv("NIX_PAGER");
    if (!pager) pager = getenv("PAGER");
    if (pager && ((string) pager == "" || (string) pager == "cat")) return;

    Pipe toPager;
    toPager.create();

    pid = startProcess([&]() {
        if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
            throw SysError("dupping stdin");
        if (!getenv("LESS"))
            setenv("LESS", "FRSXMK", 1);
        restoreSignals();
        if (pager)
            execl("/bin/sh", "sh", "-c", pager, (char *)NULL);
        execlp("pager", "pager", (char *)NULL);
        execlp("less", "less", (char *)NULL);
        execlp("more", "more", (char *)NULL);
        throw SysError(format("executing '%1%'") % pager);
    });

    pid.setKillSignal(SIGINT);

    if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
        throw SysError("dupping stdout");
}

RunPager::~RunPager()
{
    try {
        if (pid != -1) {
            std::cout.flush();
            close(STDOUT_FILENO);
            pid.wait();
        }
    } catch (...) {
        ignoreException();
    }
}

string showBytes(unsigned long long bytes)
{
    return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
}

PrintFreed::~PrintFreed()
{
    if (show)
        std::cout << format("%1% store paths deleted, %2% freed\n")
            % results.paths.size()
            % showBytes(results.bytesFreed);
}

Exit::~Exit() { }

}
<|endoftext|>


<commit_before>#include "globals.hh"
#include "shared.hh"
#include "store-api.hh"
#include "util.hh"
#include "loggers.hh"

#include <algorithm>
#include <cctype>
#include <exception>
#include <iostream>
#include <mutex>

#include <cstdlib>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>

#include <openssl/crypto.h>

namespace nix {

static bool gcWarning = true;

void printGCWarning()
{
    if (!gcWarning) return;
    static bool haveWarned = false;
    warnOnce(haveWarned,
        "you did not specify '--add-root'; "
        "the result might be removed by the garbage collector");
}

void printMissing(ref<Store> store, const std::vector<StorePathWithOutputs> & paths, Verbosity lvl)
{
    unsigned long long downloadSize, narSize;
    StorePathSet willBuild, willSubstitute, unknown;
    store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
    printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl);
}

void printMissing(ref<Store> store, const StorePathSet & willBuild,
    const StorePathSet & willSubstitute, const StorePathSet & unknown,
    unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl)
{
    if (!willBuild.empty()) {
        if (willBuild.size() == 1)
            printMsg(lvl, fmt("this derivation will be built:"));
        else
            printMsg(lvl, fmt("these %d derivations will be built:", willBuild.size()));
        auto sorted = store->topoSortPaths(willBuild);
        reverse(sorted.begin(), sorted.end());
        for (auto & i : sorted)
            printMsg(lvl, fmt("  %s", store->printStorePath(i)));
    }

    if (!willSubstitute.empty()) {
        const float downloadSizeMiB = downloadSize / (1024.f * 1024.f);
        const float narSizeMiB = narSize / (1024.f * 1024.f);
        if (willSubstitute.size() == 1) {
            printMsg(lvl, fmt("this path will be fetched (%.2f MiB download, %.2f MiB unpacked):",
                downloadSizeMiB,
                narSizeMiB));
        } else {
            printMsg(lvl, fmt("these %d paths will be fetched (%.2f MiB download, %.2f MiB unpacked):",
                willSubstitute.size(),
                downloadSizeMiB,
                narSizeMiB));
        }
        for (auto & i : willSubstitute)
            printMsg(lvl, fmt("  %s", store->printStorePath(i)));
    }

    if (!unknown.empty()) {
        printMsg(lvl, fmt("don't know how to build these paths%s:",
                (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")));
        for (auto & i : unknown)
            printMsg(lvl, fmt("  %s", store->printStorePath(i)));
    }
}

string getArg(const string & opt,
    Strings::iterator & i, const Strings::iterator & end)
{
    ++i;
    if (i == end) throw UsageError("'%1%' requires an argument", opt);
    return *i;
}

#if OPENSSL_VERSION_NUMBER < 0x10101000L
/* OpenSSL is not thread-safe by default - it will randomly crash
   unless the user supplies a mutex locking function. So let's do
   that. */
static std::vector<std::mutex> opensslLocks;

static void opensslLockCallback(int mode, int type, const char * file, int line)
{
    if (mode & CRYPTO_LOCK)
        opensslLocks[type].lock();
    else
        opensslLocks[type].unlock();
}
#endif

static void sigHandler(int signo) { }

void initNix()
{
    /* Turn on buffering for cerr. */
#if HAVE_PUBSETBUF
    static char buf[1024];
    std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
#endif

#if OPENSSL_VERSION_NUMBER < 0x10101000L
    /* Initialise OpenSSL locking. */
    opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
    CRYPTO_set_locking_callback(opensslLockCallback);
#endif

    loadConfFile();

    startSignalHandlerThread();

    /* Reset SIGCHLD to its default. */
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_handler = SIG_DFL;
    act.sa_flags = 0;
    if (sigaction(SIGCHLD, &act, 0))
        throw SysError("resetting SIGCHLD");

    /* Install a dummy SIGUSR1 handler for use with pthread_kill(). */
    act.sa_handler = sigHandler;
    if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1");

#if __APPLE__
    /* HACK: on darwin, we need can’t use sigprocmask with SIGWINCH.
     * Instead, add a dummy sigaction handler, and signalHandlerThread
     * can handle the rest. */
    struct sigaction sa;
    sa.sa_handler = sigHandler;
    if (sigaction(SIGWINCH, &sa, 0)) throw SysError("handling SIGWINCH");
#endif

    /* Register a SIGSEGV handler to detect stack overflows. */
    detectStackOverflow();

    /* There is no privacy in the Nix system ;-)  At least not for
       now.  In particular, store objects should be readable by
       everybody. */
    umask(0022);

    /* Initialise the PRNG. */
    struct timeval tv;
    gettimeofday(&tv, 0);
    srandom(tv.tv_usec);

    /* On macOS, don't use the per-session TMPDIR (as set e.g. by
       sshd). This breaks build users because they don't have access
       to the TMPDIR, in particular in ‘nix-store --serve’. */
#if __APPLE__
    if (hasPrefix(getEnv("TMPDIR").value_or("/tmp"), "/var/folders/"))
        unsetenv("TMPDIR");
#endif
}

LegacyArgs::LegacyArgs(const std::string & programName,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
    : MixCommonArgs(programName), parseArg(parseArg)
{
    addFlag({
        .longName = "no-build-output",
        .shortName = 'Q',
        .description = "do not show build output",
        .handler = {[&]() {setLogFormat(LogFormat::raw); }},
    });

    addFlag({
        .longName = "keep-failed",
        .shortName ='K',
        .description = "keep temporary directories of failed builds",
        .handler = {&(bool&) settings.keepFailed, true},
    });

    addFlag({
        .longName = "keep-going",
        .shortName ='k',
        .description = "keep going after a build fails",
        .handler = {&(bool&) settings.keepGoing, true},
    });

    addFlag({
        .longName = "fallback",
        .description = "build from source if substitution fails",
        .handler = {&(bool&) settings.tryFallback, true},
    });

    auto intSettingAlias = [&](char shortName, const std::string & longName,
        const std::string & description, const std::string & dest) {
        mkFlag<unsigned int>(shortName, longName, description, [=](unsigned int n) {
            settings.set(dest, std::to_string(n));
        });
    };

    intSettingAlias(0, "cores", "maximum number of CPU cores to use inside a build", "cores");
    intSettingAlias(0, "max-silent-time", "number of seconds of silence before a build is killed", "max-silent-time");
    intSettingAlias(0, "timeout", "number of seconds before a build is killed", "timeout");

    mkFlag(0, "readonly-mode", "do not write to the Nix store",
        &settings.readOnlyMode);

    mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'",
        &gcWarning, false);

    addFlag({
        .longName = "store",
        .description = "URI of the Nix store to use",
        .labels = {"store-uri"},
        .handler = {&(std::string&) settings.storeUri},
    });
}

bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end)
{
    if (MixCommonArgs::processFlag(pos, end)) return true;
    bool res = parseArg(pos, end);
    if (res) ++pos;
    return res;
}

bool LegacyArgs::processArgs(const Strings & args, bool finish)
{
    if (args.empty()) return true;
    assert(args.size() == 1);
    Strings ss(args);
    auto pos = ss.begin();
    if (!parseArg(pos, ss.end()))
        throw UsageError("unexpected argument '%1%'", args.front());
    return true;
}

void parseCmdLine(int argc, char * * argv,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    parseCmdLine(std::string(baseNameOf(argv[0])), argvToStrings(argc, argv), parseArg);
}

void parseCmdLine(const string & programName, const Strings & args,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    LegacyArgs(programName, parseArg).parseCmdline(args);
}

void printVersion(const string & programName)
{
    std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
    if (verbosity > lvlInfo) {
        Strings cfg;
#if HAVE_BOEHMGC
        cfg.push_back("gc");
#endif
#if HAVE_SODIUM
        cfg.push_back("signed-caches");
#endif
        std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n";
        std::cout << "System configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
        std::cout << "User configuration files: " <<
            concatStringsSep(":", settings.nixUserConfFiles)
            << "\n";
        std::cout << "Store directory: " << settings.nixStore << "\n";
        std::cout << "State directory: " << settings.nixStateDir << "\n";
    }
    throw Exit();
}

void showManPage(const string & name)
{
    restoreSignals();
    setenv("MANPATH", settings.nixManDir.c_str(), 1);
    execlp("man", "man", name.c_str(), nullptr);
    throw SysError("command 'man %1%' failed", name.c_str());
}

int handleExceptions(const string & programName, std::function<void()> fun)
{
    ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this

    ErrorInfo::programName = baseNameOf(programName);

    string error = ANSI_RED "error:" ANSI_NORMAL " ";
    try {
        try {
            fun();
        } catch (...) {
            /* Subtle: we have to make sure that any `interrupted'
               condition is discharged before we reach printMsg()
               below, since otherwise it will throw an (uncaught)
               exception. */
            setInterruptThrown();
            throw;
        }
    } catch (Exit & e) {
        return e.status;
    } catch (UsageError & e) {
        logError(e.info());
        printError("Try '%1% --help' for more information.", programName);
        return 1;
    } catch (BaseError & e) {
        logError(e.info());
        if (e.hasTrace() && !loggerSettings.showTrace.get())
            printError("(use '--show-trace' to show detailed location information)");
        return e.status;
    } catch (std::bad_alloc & e) {
        printError(error + "out of memory");
        return 1;
    } catch (std::exception & e) {
        printError(error + e.what());
        return 1;
    }

    return 0;
}

RunPager::RunPager()
{
    if (!isatty(STDOUT_FILENO)) return;
    char * pager = getenv("NIX_PAGER");
    if (!pager) pager = getenv("PAGER");
    if (pager && ((string) pager == "" || (string) pager == "cat")) return;

    Pipe toPager;
    toPager.create();

    pid = startProcess([&]() {
        if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
            throw SysError("dupping stdin");
        if (!getenv("LESS"))
            setenv("LESS", "FRSXMK", 1);
        restoreSignals();
        if (pager)
            execl("/bin/sh", "sh", "-c", pager, nullptr);
        execlp("pager", "pager", nullptr);
        execlp("less", "less", nullptr);
        execlp("more", "more", nullptr);
        throw SysError("executing '%1%'", pager);
    });

    pid.setKillSignal(SIGINT);

    if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
        throw SysError("dupping stdout");
}

RunPager::~RunPager()
{
    try {
        if (pid != -1) {
            std::cout.flush();
            close(STDOUT_FILENO);
            pid.wait();
        }
    } catch (...) {
        ignoreException();
    }
}

string showBytes(unsigned long long bytes)
{
    return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
}

PrintFreed::~PrintFreed()
{
    if (show)
        std::cout << format("%1% store paths deleted, %2% freed\n")
            % results.paths.size()
            % showBytes(results.bytesFreed);
}

Exit::~Exit() { }

}
<commit_msg>printVersion(): Show system types<commit_after>#include "globals.hh"
#include "shared.hh"
#include "store-api.hh"
#include "util.hh"
#include "loggers.hh"

#include <algorithm>
#include <cctype>
#include <exception>
#include <iostream>
#include <mutex>

#include <cstdlib>
#include <sys/time.h>
#include <sys/stat.h>
#include <unistd.h>
#include <signal.h>

#include <openssl/crypto.h>

namespace nix {

static bool gcWarning = true;

void printGCWarning()
{
    if (!gcWarning) return;
    static bool haveWarned = false;
    warnOnce(haveWarned,
        "you did not specify '--add-root'; "
        "the result might be removed by the garbage collector");
}

void printMissing(ref<Store> store, const std::vector<StorePathWithOutputs> & paths, Verbosity lvl)
{
    unsigned long long downloadSize, narSize;
    StorePathSet willBuild, willSubstitute, unknown;
    store->queryMissing(paths, willBuild, willSubstitute, unknown, downloadSize, narSize);
    printMissing(store, willBuild, willSubstitute, unknown, downloadSize, narSize, lvl);
}

void printMissing(ref<Store> store, const StorePathSet & willBuild,
    const StorePathSet & willSubstitute, const StorePathSet & unknown,
    unsigned long long downloadSize, unsigned long long narSize, Verbosity lvl)
{
    if (!willBuild.empty()) {
        if (willBuild.size() == 1)
            printMsg(lvl, fmt("this derivation will be built:"));
        else
            printMsg(lvl, fmt("these %d derivations will be built:", willBuild.size()));
        auto sorted = store->topoSortPaths(willBuild);
        reverse(sorted.begin(), sorted.end());
        for (auto & i : sorted)
            printMsg(lvl, fmt("  %s", store->printStorePath(i)));
    }

    if (!willSubstitute.empty()) {
        const float downloadSizeMiB = downloadSize / (1024.f * 1024.f);
        const float narSizeMiB = narSize / (1024.f * 1024.f);
        if (willSubstitute.size() == 1) {
            printMsg(lvl, fmt("this path will be fetched (%.2f MiB download, %.2f MiB unpacked):",
                downloadSizeMiB,
                narSizeMiB));
        } else {
            printMsg(lvl, fmt("these %d paths will be fetched (%.2f MiB download, %.2f MiB unpacked):",
                willSubstitute.size(),
                downloadSizeMiB,
                narSizeMiB));
        }
        for (auto & i : willSubstitute)
            printMsg(lvl, fmt("  %s", store->printStorePath(i)));
    }

    if (!unknown.empty()) {
        printMsg(lvl, fmt("don't know how to build these paths%s:",
                (settings.readOnlyMode ? " (may be caused by read-only store access)" : "")));
        for (auto & i : unknown)
            printMsg(lvl, fmt("  %s", store->printStorePath(i)));
    }
}

string getArg(const string & opt,
    Strings::iterator & i, const Strings::iterator & end)
{
    ++i;
    if (i == end) throw UsageError("'%1%' requires an argument", opt);
    return *i;
}

#if OPENSSL_VERSION_NUMBER < 0x10101000L
/* OpenSSL is not thread-safe by default - it will randomly crash
   unless the user supplies a mutex locking function. So let's do
   that. */
static std::vector<std::mutex> opensslLocks;

static void opensslLockCallback(int mode, int type, const char * file, int line)
{
    if (mode & CRYPTO_LOCK)
        opensslLocks[type].lock();
    else
        opensslLocks[type].unlock();
}
#endif

static void sigHandler(int signo) { }

void initNix()
{
    /* Turn on buffering for cerr. */
#if HAVE_PUBSETBUF
    static char buf[1024];
    std::cerr.rdbuf()->pubsetbuf(buf, sizeof(buf));
#endif

#if OPENSSL_VERSION_NUMBER < 0x10101000L
    /* Initialise OpenSSL locking. */
    opensslLocks = std::vector<std::mutex>(CRYPTO_num_locks());
    CRYPTO_set_locking_callback(opensslLockCallback);
#endif

    loadConfFile();

    startSignalHandlerThread();

    /* Reset SIGCHLD to its default. */
    struct sigaction act;
    sigemptyset(&act.sa_mask);
    act.sa_handler = SIG_DFL;
    act.sa_flags = 0;
    if (sigaction(SIGCHLD, &act, 0))
        throw SysError("resetting SIGCHLD");

    /* Install a dummy SIGUSR1 handler for use with pthread_kill(). */
    act.sa_handler = sigHandler;
    if (sigaction(SIGUSR1, &act, 0)) throw SysError("handling SIGUSR1");

#if __APPLE__
    /* HACK: on darwin, we need can’t use sigprocmask with SIGWINCH.
     * Instead, add a dummy sigaction handler, and signalHandlerThread
     * can handle the rest. */
    struct sigaction sa;
    sa.sa_handler = sigHandler;
    if (sigaction(SIGWINCH, &sa, 0)) throw SysError("handling SIGWINCH");
#endif

    /* Register a SIGSEGV handler to detect stack overflows. */
    detectStackOverflow();

    /* There is no privacy in the Nix system ;-)  At least not for
       now.  In particular, store objects should be readable by
       everybody. */
    umask(0022);

    /* Initialise the PRNG. */
    struct timeval tv;
    gettimeofday(&tv, 0);
    srandom(tv.tv_usec);

    /* On macOS, don't use the per-session TMPDIR (as set e.g. by
       sshd). This breaks build users because they don't have access
       to the TMPDIR, in particular in ‘nix-store --serve’. */
#if __APPLE__
    if (hasPrefix(getEnv("TMPDIR").value_or("/tmp"), "/var/folders/"))
        unsetenv("TMPDIR");
#endif
}

LegacyArgs::LegacyArgs(const std::string & programName,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
    : MixCommonArgs(programName), parseArg(parseArg)
{
    addFlag({
        .longName = "no-build-output",
        .shortName = 'Q',
        .description = "do not show build output",
        .handler = {[&]() {setLogFormat(LogFormat::raw); }},
    });

    addFlag({
        .longName = "keep-failed",
        .shortName ='K',
        .description = "keep temporary directories of failed builds",
        .handler = {&(bool&) settings.keepFailed, true},
    });

    addFlag({
        .longName = "keep-going",
        .shortName ='k',
        .description = "keep going after a build fails",
        .handler = {&(bool&) settings.keepGoing, true},
    });

    addFlag({
        .longName = "fallback",
        .description = "build from source if substitution fails",
        .handler = {&(bool&) settings.tryFallback, true},
    });

    auto intSettingAlias = [&](char shortName, const std::string & longName,
        const std::string & description, const std::string & dest) {
        mkFlag<unsigned int>(shortName, longName, description, [=](unsigned int n) {
            settings.set(dest, std::to_string(n));
        });
    };

    intSettingAlias(0, "cores", "maximum number of CPU cores to use inside a build", "cores");
    intSettingAlias(0, "max-silent-time", "number of seconds of silence before a build is killed", "max-silent-time");
    intSettingAlias(0, "timeout", "number of seconds before a build is killed", "timeout");

    mkFlag(0, "readonly-mode", "do not write to the Nix store",
        &settings.readOnlyMode);

    mkFlag(0, "no-gc-warning", "disable warning about not using '--add-root'",
        &gcWarning, false);

    addFlag({
        .longName = "store",
        .description = "URI of the Nix store to use",
        .labels = {"store-uri"},
        .handler = {&(std::string&) settings.storeUri},
    });
}

bool LegacyArgs::processFlag(Strings::iterator & pos, Strings::iterator end)
{
    if (MixCommonArgs::processFlag(pos, end)) return true;
    bool res = parseArg(pos, end);
    if (res) ++pos;
    return res;
}

bool LegacyArgs::processArgs(const Strings & args, bool finish)
{
    if (args.empty()) return true;
    assert(args.size() == 1);
    Strings ss(args);
    auto pos = ss.begin();
    if (!parseArg(pos, ss.end()))
        throw UsageError("unexpected argument '%1%'", args.front());
    return true;
}

void parseCmdLine(int argc, char * * argv,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    parseCmdLine(std::string(baseNameOf(argv[0])), argvToStrings(argc, argv), parseArg);
}

void parseCmdLine(const string & programName, const Strings & args,
    std::function<bool(Strings::iterator & arg, const Strings::iterator & end)> parseArg)
{
    LegacyArgs(programName, parseArg).parseCmdline(args);
}

void printVersion(const string & programName)
{
    std::cout << format("%1% (Nix) %2%") % programName % nixVersion << std::endl;
    if (verbosity > lvlInfo) {
        Strings cfg;
#if HAVE_BOEHMGC
        cfg.push_back("gc");
#endif
#if HAVE_SODIUM
        cfg.push_back("signed-caches");
#endif
        std::cout << "System type: " << settings.thisSystem << "\n";
        std::cout << "Additional system types: " << concatStringsSep(", ", settings.extraPlatforms.get()) << "\n";
        std::cout << "Features: " << concatStringsSep(", ", cfg) << "\n";
        std::cout << "System configuration file: " << settings.nixConfDir + "/nix.conf" << "\n";
        std::cout << "User configuration files: " <<
            concatStringsSep(":", settings.nixUserConfFiles)
            << "\n";
        std::cout << "Store directory: " << settings.nixStore << "\n";
        std::cout << "State directory: " << settings.nixStateDir << "\n";
    }
    throw Exit();
}

void showManPage(const string & name)
{
    restoreSignals();
    setenv("MANPATH", settings.nixManDir.c_str(), 1);
    execlp("man", "man", name.c_str(), nullptr);
    throw SysError("command 'man %1%' failed", name.c_str());
}

int handleExceptions(const string & programName, std::function<void()> fun)
{
    ReceiveInterrupts receiveInterrupts; // FIXME: need better place for this

    ErrorInfo::programName = baseNameOf(programName);

    string error = ANSI_RED "error:" ANSI_NORMAL " ";
    try {
        try {
            fun();
        } catch (...) {
            /* Subtle: we have to make sure that any `interrupted'
               condition is discharged before we reach printMsg()
               below, since otherwise it will throw an (uncaught)
               exception. */
            setInterruptThrown();
            throw;
        }
    } catch (Exit & e) {
        return e.status;
    } catch (UsageError & e) {
        logError(e.info());
        printError("Try '%1% --help' for more information.", programName);
        return 1;
    } catch (BaseError & e) {
        logError(e.info());
        if (e.hasTrace() && !loggerSettings.showTrace.get())
            printError("(use '--show-trace' to show detailed location information)");
        return e.status;
    } catch (std::bad_alloc & e) {
        printError(error + "out of memory");
        return 1;
    } catch (std::exception & e) {
        printError(error + e.what());
        return 1;
    }

    return 0;
}

RunPager::RunPager()
{
    if (!isatty(STDOUT_FILENO)) return;
    char * pager = getenv("NIX_PAGER");
    if (!pager) pager = getenv("PAGER");
    if (pager && ((string) pager == "" || (string) pager == "cat")) return;

    Pipe toPager;
    toPager.create();

    pid = startProcess([&]() {
        if (dup2(toPager.readSide.get(), STDIN_FILENO) == -1)
            throw SysError("dupping stdin");
        if (!getenv("LESS"))
            setenv("LESS", "FRSXMK", 1);
        restoreSignals();
        if (pager)
            execl("/bin/sh", "sh", "-c", pager, nullptr);
        execlp("pager", "pager", nullptr);
        execlp("less", "less", nullptr);
        execlp("more", "more", nullptr);
        throw SysError("executing '%1%'", pager);
    });

    pid.setKillSignal(SIGINT);

    if (dup2(toPager.writeSide.get(), STDOUT_FILENO) == -1)
        throw SysError("dupping stdout");
}

RunPager::~RunPager()
{
    try {
        if (pid != -1) {
            std::cout.flush();
            close(STDOUT_FILENO);
            pid.wait();
        }
    } catch (...) {
        ignoreException();
    }
}

string showBytes(unsigned long long bytes)
{
    return (format("%.2f MiB") % (bytes / (1024.0 * 1024.0))).str();
}

PrintFreed::~PrintFreed()
{
    if (show)
        std::cout << format("%1% store paths deleted, %2% freed\n")
            % results.paths.size()
            % showBytes(results.bytesFreed);
}

Exit::~Exit() { }

}
<|endoftext|>


<commit_before>/* Copyright (C) 2005-2008, Thorvald Natvig <thorvald@natvig.com>

   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 the Mumble Developers 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 FOUNDATION 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 "ConfigDialog.h"
#include "AudioInput.h"
#include "AudioOutput.h"
#include "Global.h"

QMap<int, ConfigWidgetNew> *ConfigRegistrar::c_qmNew;

ConfigRegistrar::ConfigRegistrar(int priority, ConfigWidgetNew n) {
	if (! c_qmNew)
		c_qmNew = new QMap<int, ConfigWidgetNew>();
	c_qmNew->insert(priority,n);
}

ConfigWidget::ConfigWidget(Settings &st) : s(st) {
}

QIcon ConfigWidget::icon() const {
	return qApp->windowIcon();
}

void ConfigWidget::accept() const {
}

void ConfigWidget::loadSlider(QSlider *s, int v) {
	if (v != s->value()) {
		s->setValue(v);
	} else if (v != s->minimum()) {
		s->setValue(s->minimum());
		s->setValue(v);
	} else {
		s->setValue(s->maximum());
		s->setValue(v);
	}
}

void ConfigWidget::loadCheckBox(QAbstractButton *c, bool v) {
	c->setChecked(! v);
	c->setChecked(v);
}

void ConfigWidget::loadComboBox(QComboBox *c, int v) {
	if (c->currentIndex() != v) {
		c->setCurrentIndex(v);
	} else if (v != 0) {
		c->setCurrentIndex(0);
		c->setCurrentIndex(v);
	} else if (c->count() >= 2) {
		c->setCurrentIndex(1);
		c->setCurrentIndex(v);
	}
}

ConfigDialog::ConfigDialog(QWidget *p) : QDialog(p) {
	setupUi(this);

	s = g.s;

	QWidget *w;
	while ((w = qswPages->widget(0)))
		delete w;

	qcbExpert->setChecked(g.s.bExpert);

	ConfigWidgetNew cwn;
	foreach(cwn, *ConfigRegistrar::c_qmNew) {
		addPage(cwn(s));
	}

	if (qlwIcons->count() > 0)
		qlwIcons->setCurrentItem(qlwIcons->item(0));

	on_qcbExpert_clicked(g.s.bExpert);

	QPushButton *okButton = dialogButtonBox->button(QDialogButtonBox::Ok);
	okButton->setToolTip(tr("Accept changes"));
	okButton->setWhatsThis(tr("This button will accept current settings and return to the application.
"
	                          "The settings will be stored to disk when you leave the application."));

	QPushButton *cancelButton = dialogButtonBox->button(QDialogButtonBox::Cancel);
	cancelButton->setToolTip(tr("Reject changes"));
	cancelButton->setWhatsThis(tr("This button will reject all changes and return to the application.
"
	                              "The settings will be reset to the previous positions."));

	QPushButton *applyButton = dialogButtonBox->button(QDialogButtonBox::Apply);
	applyButton->setToolTip(tr("Apply changes"));
	applyButton->setWhatsThis(tr("This button will immediately apply all changes."));

	QPushButton *resetButton = pageButtonBox->button(QDialogButtonBox::Reset);
	resetButton->setToolTip(tr("Undo changes for current page"));
	resetButton->setWhatsThis(tr("This button will revert any changes done on the current page to the most recent applied settings."));

	QPushButton *restoreButton = pageButtonBox->button(QDialogButtonBox::RestoreDefaults);
	restoreButton->setToolTip(tr("Restore defaults for current page"));
	restoreButton->setWhatsThis(tr("This button will restore the settings for the current page only to their defaults. Other pages will be not be changed.
"
	                               "To restore all settings to their defaults, you will have to use this button on every page."
	                              ));

}

void ConfigDialog::addPage(ConfigWidget *cw) {
	QDesktopWidget dw;

	QRect ds=dw.availableGeometry(this);
	QSize ms=cw->minimumSizeHint();
	cw->resize(ms);
	cw->setMinimumSize(ms);

	ms.rwidth() += 128;
	ms.rheight() += 64;
	if ((ms.width() > ds.width()) || (ms.height() > ds.height())) {
		QScrollArea *qsa=new QScrollArea(this);
		qsa->setWidgetResizable(true);
		qsa->setWidget(cw);
		qswPages->addWidget(qsa);
		qWarning("Widget %s has size %d %d (%d %d)", qPrintable(cw->title()), ms.width(), ms.height(),ds.width(), ds.height());
	} else {
		qswPages->addWidget(cw);
	}
	QListWidgetItem *i = new QListWidgetItem(qlwIcons);
	i->setIcon(cw->icon());
	i->setText(cw->title());
	i->setTextAlignment(Qt::AlignHCenter);
	i->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);

	widgets << cw;
	cw->load(g.s);
}

void ConfigDialog::on_qlwIcons_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) {
	if (!current)
		current = previous;

	if (current)
		qswPages->setCurrentIndex(qlwIcons->row(current));
}

void ConfigDialog::on_pageButtonBox_clicked(QAbstractButton *b) {
	ConfigWidget *conf = qobject_cast<ConfigWidget *>(qswPages->currentWidget());
	switch (pageButtonBox->standardButton(b)) {
		case QDialogButtonBox::RestoreDefaults: {
				Settings def;
				if (conf)
					conf->load(def);
				break;
			}
		case QDialogButtonBox::Reset: {
				if (conf)
					conf->load(g.s);
				break;
			}
		default:
			break;
	}
}

void ConfigDialog::on_dialogButtonBox_clicked(QAbstractButton *b) {
	switch (dialogButtonBox->standardButton(b)) {
		case QDialogButtonBox::Apply: {
				apply();
				break;
			}
		default:
			break;
	}
}

void ConfigDialog::on_qcbExpert_clicked(bool b) {
	int idx = 0;
	foreach(ConfigWidget *cw, widgets) {
		bool showit = cw->expert(b);
		showit = showit || b;
		QListWidgetItem *qlwi = qlwIcons->item(idx++);
		if (qlwi)
			qlwi->setHidden(!showit);
	}
}

void ConfigDialog::apply() {
	foreach(ConfigWidget *cw, widgets)
	cw->save();

	boost::weak_ptr<AudioInput> wai(g.ai);
	boost::weak_ptr<AudioOutput> wao(g.ao);

	g.ai.reset();
	g.ao.reset();

	while (! wai.expired() || ! wao.expired()) {
		// Where is QThread::yield() ?
	}

	g.s = s;

	foreach(ConfigWidget *cw, widgets)
	cw->accept();

	g.ai = AudioInputRegistrar::newFromChoice(g.s.qsAudioInput);
	g.ai->start(QThread::HighestPriority);
	g.ao = AudioOutputRegistrar::newFromChoice(g.s.qsAudioOutput);
	g.ao->start(QThread::HighPriority);

	// They might have changed their keys.
	g.iPushToTalk = 0;
	g.iAltSpeak = 0;

	g.s.bExpert = qcbExpert->isChecked();
}

void ConfigDialog::accept() {
	apply();
	QDialog::accept();
}
<commit_msg>Increase safety size for config widgets<commit_after>/* Copyright (C) 2005-2008, Thorvald Natvig <thorvald@natvig.com>

   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 the Mumble Developers 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 FOUNDATION 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 "ConfigDialog.h"
#include "AudioInput.h"
#include "AudioOutput.h"
#include "Global.h"

QMap<int, ConfigWidgetNew> *ConfigRegistrar::c_qmNew;

ConfigRegistrar::ConfigRegistrar(int priority, ConfigWidgetNew n) {
	if (! c_qmNew)
		c_qmNew = new QMap<int, ConfigWidgetNew>();
	c_qmNew->insert(priority,n);
}

ConfigWidget::ConfigWidget(Settings &st) : s(st) {
}

QIcon ConfigWidget::icon() const {
	return qApp->windowIcon();
}

void ConfigWidget::accept() const {
}

void ConfigWidget::loadSlider(QSlider *s, int v) {
	if (v != s->value()) {
		s->setValue(v);
	} else if (v != s->minimum()) {
		s->setValue(s->minimum());
		s->setValue(v);
	} else {
		s->setValue(s->maximum());
		s->setValue(v);
	}
}

void ConfigWidget::loadCheckBox(QAbstractButton *c, bool v) {
	c->setChecked(! v);
	c->setChecked(v);
}

void ConfigWidget::loadComboBox(QComboBox *c, int v) {
	if (c->currentIndex() != v) {
		c->setCurrentIndex(v);
	} else if (v != 0) {
		c->setCurrentIndex(0);
		c->setCurrentIndex(v);
	} else if (c->count() >= 2) {
		c->setCurrentIndex(1);
		c->setCurrentIndex(v);
	}
}

ConfigDialog::ConfigDialog(QWidget *p) : QDialog(p) {
	setupUi(this);

	s = g.s;

	QWidget *w;
	while ((w = qswPages->widget(0)))
		delete w;

	qcbExpert->setChecked(g.s.bExpert);

	ConfigWidgetNew cwn;
	foreach(cwn, *ConfigRegistrar::c_qmNew) {
		addPage(cwn(s));
	}

	if (qlwIcons->count() > 0)
		qlwIcons->setCurrentItem(qlwIcons->item(0));

	on_qcbExpert_clicked(g.s.bExpert);

	QPushButton *okButton = dialogButtonBox->button(QDialogButtonBox::Ok);
	okButton->setToolTip(tr("Accept changes"));
	okButton->setWhatsThis(tr("This button will accept current settings and return to the application.
"
	                          "The settings will be stored to disk when you leave the application."));

	QPushButton *cancelButton = dialogButtonBox->button(QDialogButtonBox::Cancel);
	cancelButton->setToolTip(tr("Reject changes"));
	cancelButton->setWhatsThis(tr("This button will reject all changes and return to the application.
"
	                              "The settings will be reset to the previous positions."));

	QPushButton *applyButton = dialogButtonBox->button(QDialogButtonBox::Apply);
	applyButton->setToolTip(tr("Apply changes"));
	applyButton->setWhatsThis(tr("This button will immediately apply all changes."));

	QPushButton *resetButton = pageButtonBox->button(QDialogButtonBox::Reset);
	resetButton->setToolTip(tr("Undo changes for current page"));
	resetButton->setWhatsThis(tr("This button will revert any changes done on the current page to the most recent applied settings."));

	QPushButton *restoreButton = pageButtonBox->button(QDialogButtonBox::RestoreDefaults);
	restoreButton->setToolTip(tr("Restore defaults for current page"));
	restoreButton->setWhatsThis(tr("This button will restore the settings for the current page only to their defaults. Other pages will be not be changed.
"
	                               "To restore all settings to their defaults, you will have to use this button on every page."
	                              ));

}

void ConfigDialog::addPage(ConfigWidget *cw) {
	QDesktopWidget dw;

	QRect ds=dw.availableGeometry(this);
	QSize ms=cw->minimumSizeHint();
	cw->resize(ms);
	cw->setMinimumSize(ms);

	ms.rwidth() += 128;
	ms.rheight() += 192;
	if ((ms.width() > ds.width()) || (ms.height() > ds.height())) {
		QScrollArea *qsa=new QScrollArea(this);
		qsa->setWidgetResizable(true);
		qsa->setWidget(cw);
		qswPages->addWidget(qsa);
		qWarning("Widget %s has size %d %d (%d %d)", qPrintable(cw->title()), ms.width(), ms.height(),ds.width(), ds.height());
	} else {
		qswPages->addWidget(cw);
	}
	QListWidgetItem *i = new QListWidgetItem(qlwIcons);
	i->setIcon(cw->icon());
	i->setText(cw->title());
	i->setTextAlignment(Qt::AlignHCenter);
	i->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);

	widgets << cw;
	cw->load(g.s);
}

void ConfigDialog::on_qlwIcons_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) {
	if (!current)
		current = previous;

	if (current)
		qswPages->setCurrentIndex(qlwIcons->row(current));
}

void ConfigDialog::on_pageButtonBox_clicked(QAbstractButton *b) {
	ConfigWidget *conf = qobject_cast<ConfigWidget *>(qswPages->currentWidget());
	switch (pageButtonBox->standardButton(b)) {
		case QDialogButtonBox::RestoreDefaults: {
				Settings def;
				if (conf)
					conf->load(def);
				break;
			}
		case QDialogButtonBox::Reset: {
				if (conf)
					conf->load(g.s);
				break;
			}
		default:
			break;
	}
}

void ConfigDialog::on_dialogButtonBox_clicked(QAbstractButton *b) {
	switch (dialogButtonBox->standardButton(b)) {
		case QDialogButtonBox::Apply: {
				apply();
				break;
			}
		default:
			break;
	}
}

void ConfigDialog::on_qcbExpert_clicked(bool b) {
	int idx = 0;
	foreach(ConfigWidget *cw, widgets) {
		bool showit = cw->expert(b);
		showit = showit || b;
		QListWidgetItem *qlwi = qlwIcons->item(idx++);
		if (qlwi)
			qlwi->setHidden(!showit);
	}
}

void ConfigDialog::apply() {
	foreach(ConfigWidget *cw, widgets)
	cw->save();

	boost::weak_ptr<AudioInput> wai(g.ai);
	boost::weak_ptr<AudioOutput> wao(g.ao);

	g.ai.reset();
	g.ao.reset();

	while (! wai.expired() || ! wao.expired()) {
		// Where is QThread::yield() ?
	}

	g.s = s;

	foreach(ConfigWidget *cw, widgets)
	cw->accept();

	g.ai = AudioInputRegistrar::newFromChoice(g.s.qsAudioInput);
	g.ai->start(QThread::HighestPriority);
	g.ao = AudioOutputRegistrar::newFromChoice(g.s.qsAudioOutput);
	g.ao->start(QThread::HighPriority);

	// They might have changed their keys.
	g.iPushToTalk = 0;
	g.iAltSpeak = 0;

	g.s.bExpert = qcbExpert->isChecked();
}

void ConfigDialog::accept() {
	apply();
	QDialog::accept();
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "rpcnestedtests.h"

#include "chainparams.h"
#include "consensus/validation.h"
#include "validation.h"
#include "rpc/register.h"
#include "rpc/server.h"
#include "rpcconsole.h"
#include "test/testutil.h"
#include "univalue.h"
#include "util.h"

#include <QDir>
#include <QtGlobal>

#include <boost/filesystem.hpp>

static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
{
    if (request.fHelp) {
        return "help message";
    }
    return request.params.write(0, 0);
}

static const CRPCCommand vRPCCommands[] =
{
    { "test", "rpcNestedTest", &rpcNestedTest_rpc, true, {} },
};

void RPCNestedTests::rpcNestedTests()
{
    UniValue jsonRPCError;

    // do some test setup
    // could be moved to a more generic place when we add more tests on QT level
    const CChainParams& chainparams = Params();
    RegisterAllCoreRPCCommands(tableRPC);
    tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
    ClearDatadirCache();
    std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_goldcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
    QDir dir(QString::fromStdString(path));
    dir.mkpath(".");
    ForceSetArg("-datadir", path);
    //mempool.setSanityCheck(1.0);
    pblocktree = new CBlockTreeDB(1 << 20, true);
    pcoinsdbview = new CCoinsViewDB(1 << 23, true);
    pcoinsTip = new CCoinsViewCache(pcoinsdbview);
    InitBlockIndex(chainparams);
    {
        CValidationState state;
        bool ok = ActivateBestChain(state, chainparams);
        QVERIFY(ok);
    }

    SetRPCWarmupFinished();

    std::string result;
    std::string result2;
    std::string filtered;
    RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path
    QVERIFY(result=="main");
    QVERIFY(filtered == "getblockchaininfo()[chain]");

    RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting
    RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)");

    RPCConsole::RPCExecuteCommandLine(result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter

    RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo");
    QVERIFY(result.substr(0,1) == "{");

    RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()");
    QVERIFY(result.substr(0,1) == "{");

    RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated
    QVERIFY(result.substr(0,1) == "{");

    (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key
    QVERIFY(result == "null");

    (RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
    (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
    QVERIFY(result == result2);
    (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [],  {} , 0   )")); //whitespace between parametres is allowed
    QVERIFY(result == result2);

    RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]", &filtered);
    QVERIFY(result == "97ddfbbae6be97fd6cdf3e7ca13232a3afff2353e29badfab7f73011edd4ced9");
    QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");

    RPCConsole::RPCParseCommandLine(result, "importprivkey", false, &filtered);
    QVERIFY(filtered == "importprivkey(…)");
    RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc", false, &filtered);
    QVERIFY(filtered == "signmessagewithprivkey(…)");
    RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc,def", false, &filtered);
    QVERIFY(filtered == "signmessagewithprivkey(…)");
    RPCConsole::RPCParseCommandLine(result, "signrawtransaction(abc)", false, &filtered);
    QVERIFY(filtered == "signrawtransaction(…)");
    RPCConsole::RPCParseCommandLine(result, "walletpassphrase(help())", false, &filtered);
    QVERIFY(filtered == "walletpassphrase(…)");
    RPCConsole::RPCParseCommandLine(result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
    QVERIFY(filtered == "walletpassphrasechange(…)");
    RPCConsole::RPCParseCommandLine(result, "help(encryptwallet(abc, def))", false, &filtered);
    QVERIFY(filtered == "help(encryptwallet(…))");
    RPCConsole::RPCParseCommandLine(result, "help(importprivkey())", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…))");
    RPCConsole::RPCParseCommandLine(result, "help(importprivkey(help()))", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…))");
    RPCConsole::RPCParseCommandLine(result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))");

    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest");
    QVERIFY(result == "[]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest ''");
    QVERIFY(result == "[\"\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest \"\"");
    QVERIFY(result == "[\"\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest '' abc");
    QVERIFY(result == "[\"\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc '' abc");
    QVERIFY(result == "[\"abc\",\"\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc  abc");
    QVERIFY(result == "[\"abc\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc\t\tabc");
    QVERIFY(result == "[\"abc\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc )");
    QVERIFY(result == "[\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc )");
    QVERIFY(result == "[\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(   abc   ,   cba )");
    QVERIFY(result == "[\"abc\",\"cba\"]");

#if QT_VERSION >= 0x050300
    // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
    (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
    (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using ,
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
#endif

    delete pcoinsTip;
    delete pcoinsdbview;
    delete pblocktree;

    boost::filesystem::remove_all(boost::filesystem::path(path));
}
<commit_msg>Unit Tests (#12): Fix rpcnestedtests by putting the correct transaction id for the coinbase of the genesis block of GoldCoin.<commit_after>// Copyright (c) 2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "rpcnestedtests.h"

#include "chainparams.h"
#include "consensus/validation.h"
#include "validation.h"
#include "rpc/register.h"
#include "rpc/server.h"
#include "rpcconsole.h"
#include "test/testutil.h"
#include "univalue.h"
#include "util.h"

#include <QDir>
#include <QtGlobal>

#include <boost/filesystem.hpp>

static UniValue rpcNestedTest_rpc(const JSONRPCRequest& request)
{
    if (request.fHelp) {
        return "help message";
    }
    return request.params.write(0, 0);
}

static const CRPCCommand vRPCCommands[] =
{
    { "test", "rpcNestedTest", &rpcNestedTest_rpc, true, {} },
};

void RPCNestedTests::rpcNestedTests()
{
    UniValue jsonRPCError;

    // do some test setup
    // could be moved to a more generic place when we add more tests on QT level
    const CChainParams& chainparams = Params();
    RegisterAllCoreRPCCommands(tableRPC);
    tableRPC.appendCommand("rpcNestedTest", &vRPCCommands[0]);
    ClearDatadirCache();
    std::string path = QDir::tempPath().toStdString() + "/" + strprintf("test_goldcoin_qt_%lu_%i", (unsigned long)GetTime(), (int)(GetRand(100000)));
    QDir dir(QString::fromStdString(path));
    dir.mkpath(".");
    ForceSetArg("-datadir", path);
    //mempool.setSanityCheck(1.0);
    pblocktree = new CBlockTreeDB(1 << 20, true);
    pcoinsdbview = new CCoinsViewDB(1 << 23, true);
    pcoinsTip = new CCoinsViewCache(pcoinsdbview);
    InitBlockIndex(chainparams);
    {
        CValidationState state;
        bool ok = ActivateBestChain(state, chainparams);
        QVERIFY(ok);
    }

    SetRPCWarmupFinished();

    std::string result;
    std::string result2;
    std::string filtered;
    RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[chain]", &filtered); //simple result filtering with path
    QVERIFY(result=="main");
    QVERIFY(filtered == "getblockchaininfo()[chain]");

    RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())"); //simple 2 level nesting
    RPCConsole::RPCExecuteCommandLine(result, "getblock(getblock(getbestblockhash())[hash], true)");

    RPCConsole::RPCExecuteCommandLine(result, "getblock( getblock( getblock(getbestblockhash())[hash] )[hash], true)"); //4 level nesting with whitespace, filtering path and boolean parameter

    RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo");
    QVERIFY(result.substr(0,1) == "{");

    RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()");
    QVERIFY(result.substr(0,1) == "{");

    RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo "); //whitespace at the end will be tolerated
    QVERIFY(result.substr(0,1) == "{");

    (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()[\"chain\"]")); //Quote path identifier are allowed, but look after a child contaning the quotes in the key
    QVERIFY(result == "null");

    (RPCConsole::RPCExecuteCommandLine(result, "createrawtransaction [] {} 0")); //parameter not in brackets are allowed
    (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction([],{},0)")); //parameter in brackets are allowed
    QVERIFY(result == result2);
    (RPCConsole::RPCExecuteCommandLine(result2, "createrawtransaction( [],  {} , 0   )")); //whitespace between parametres is allowed
    QVERIFY(result == result2);

    RPCConsole::RPCExecuteCommandLine(result, "getblock(getbestblockhash())[tx][0]", &filtered);
    QVERIFY(result == "a215e67ba165202f75b6458d22fedd1a3ec4f03449a4c6b2a4b8130bfebd3b15");
    QVERIFY(filtered == "getblock(getbestblockhash())[tx][0]");

    RPCConsole::RPCParseCommandLine(result, "importprivkey", false, &filtered);
    QVERIFY(filtered == "importprivkey(…)");
    RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc", false, &filtered);
    QVERIFY(filtered == "signmessagewithprivkey(…)");
    RPCConsole::RPCParseCommandLine(result, "signmessagewithprivkey abc,def", false, &filtered);
    QVERIFY(filtered == "signmessagewithprivkey(…)");
    RPCConsole::RPCParseCommandLine(result, "signrawtransaction(abc)", false, &filtered);
    QVERIFY(filtered == "signrawtransaction(…)");
    RPCConsole::RPCParseCommandLine(result, "walletpassphrase(help())", false, &filtered);
    QVERIFY(filtered == "walletpassphrase(…)");
    RPCConsole::RPCParseCommandLine(result, "walletpassphrasechange(help(walletpassphrasechange(abc)))", false, &filtered);
    QVERIFY(filtered == "walletpassphrasechange(…)");
    RPCConsole::RPCParseCommandLine(result, "help(encryptwallet(abc, def))", false, &filtered);
    QVERIFY(filtered == "help(encryptwallet(…))");
    RPCConsole::RPCParseCommandLine(result, "help(importprivkey())", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…))");
    RPCConsole::RPCParseCommandLine(result, "help(importprivkey(help()))", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…))");
    RPCConsole::RPCParseCommandLine(result, "help(importprivkey(abc), walletpassphrase(def))", false, &filtered);
    QVERIFY(filtered == "help(importprivkey(…), walletpassphrase(…))");

    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest");
    QVERIFY(result == "[]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest ''");
    QVERIFY(result == "[\"\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest \"\"");
    QVERIFY(result == "[\"\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest '' abc");
    QVERIFY(result == "[\"\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc '' abc");
    QVERIFY(result == "[\"abc\",\"\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc  abc");
    QVERIFY(result == "[\"abc\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc\t\tabc");
    QVERIFY(result == "[\"abc\",\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc )");
    QVERIFY(result == "[\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest( abc )");
    QVERIFY(result == "[\"abc\"]");
    RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(   abc   ,   cba )");
    QVERIFY(result == "[\"abc\",\"cba\"]");

#if QT_VERSION >= 0x050300
    // do the QVERIFY_EXCEPTION_THROWN checks only with Qt5.3 and higher (QVERIFY_EXCEPTION_THROWN was introduced in Qt5.3)
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() .\n"), std::runtime_error); //invalid syntax
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo() getblockchaininfo()"), std::runtime_error); //invalid syntax
    (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(")); //tolerate non closing brackets if we have no arguments
    (RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo()()()")); //tolerate non command brackts
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "getblockchaininfo(True)"), UniValue); //invalid argument
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "a(getblockchaininfo(True))"), UniValue); //method not found
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest abc,,abc"), std::runtime_error); //don't tollerate empty arguments when using ,
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,abc)"), std::runtime_error); //don't tollerate empty arguments when using ,
    QVERIFY_EXCEPTION_THROWN(RPCConsole::RPCExecuteCommandLine(result, "rpcNestedTest(abc,,)"), std::runtime_error); //don't tollerate empty arguments when using ,
#endif

    delete pcoinsTip;
    delete pcoinsdbview;
    delete pblocktree;

    boost::filesystem::remove_all(boost::filesystem::path(path));
}
<|endoftext|>


<commit_before>
#include <xpcc/architecture/platform.hpp>

using namespace xpcc::atmega;

// Create a new UART object and configure it to a baudrate of 115200
Uart0 uart(115200);

int
main()
{
	// Enable interrupts, this is needed for every buffered UART
	sei();

	// Write some characters
	uart.write('H');
	uart.write('e');
	uart.write('l');
	uart.write('l');
	uart.write('o');
	uart.write('\n');

	while (1)
	{
	}
}
<commit_msg>Fix AVR Uart exammple<commit_after>
#include <xpcc/architecture/platform.hpp>

using namespace xpcc::atmega;
typedef xpcc::avr::SystemClock clock;

// Create a new UART object and configure it to a baudrate of 115200
typedef Uart0 uart;

int
main()
{
    GpioOutputD1::connect(Uart0::Tx);
    GpioInputD0::connect(Uart0::Rx);
    uart::initialize<clock, 115200>();

    // Enable interrupts, this is needed for every buffered UART
	sei();

	// Write some characters
    uart::write('H');
    uart::write('e');
    uart::write('l');
    uart::write('l');
    uart::write('o');
    uart::write('\n');

	while (1)
	{
	}
}
<|endoftext|>