<commit_before>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#pragma warning(4: 4786)
#endif

#include <string>
#include "BZDBCache.h"

bool  BZDBCache::displayMainFlags;
bool  BZDBCache::blend;
bool  BZDBCache::texture;
bool  BZDBCache::shadows;
bool  BZDBCache::zbuffer;
bool  BZDBCache::tesselation;
bool  BZDBCache::lighting;
bool  BZDBCache::smooth;
bool  BZDBCache::colorful;
bool  BZDBCache::animatedTreads;
bool  BZDBCache::leadingShotLine;
int   BZDBCache::radarStyle;
int   BZDBCache::linedRadarShots;
int   BZDBCache::sizedRadarShots;
int   BZDBCache::flagChunks;
float BZDBCache::pulseRate;
float BZDBCache::pulseDepth;
bool  BZDBCache::showCollisionGrid;
bool  BZDBCache::showCullingGrid;

float BZDBCache::worldSize;
float BZDBCache::radarLimit;
float BZDBCache::gravity;
float BZDBCache::tankWidth;
float BZDBCache::tankLength;
float BZDBCache::tankHeight;
float BZDBCache::tankSpeed;
float BZDBCache::tankRadius;
float BZDBCache::flagRadius;
float BZDBCache::flagPoleSize;
float BZDBCache::flagPoleWidth;
float BZDBCache::maxLOD;

void BZDBCache::init()
{
  BZDB.addCallback("displayMainFlags", clientCallback, NULL);
  BZDB.addCallback("radarStyle", clientCallback, NULL);
  BZDB.addCallback("blend", clientCallback, NULL);
  BZDB.addCallback("texture", clientCallback, NULL);
  BZDB.addCallback("shadows", clientCallback, NULL);
  BZDB.addCallback("zbuffer", clientCallback, NULL);
  BZDB.addCallback("tesselation", clientCallback, NULL);
  BZDB.addCallback("lighting", clientCallback, NULL);
  BZDB.addCallback("smooth", clientCallback, NULL);
  BZDB.addCallback("colorful", clientCallback, NULL);
  BZDB.addCallback("animatedTreads", clientCallback, NULL);
  BZDB.addCallback("leadingShotLine", clientCallback, NULL);
  BZDB.addCallback("flagChunks", clientCallback, NULL);
  BZDB.addCallback("pulseRate", clientCallback, NULL);
  BZDB.addCallback("pulseDepth", clientCallback, NULL);
  BZDB.addCallback("showCollisionGrid", clientCallback, NULL);
  BZDB.addCallback("showCullingGrid", clientCallback, NULL);

  BZDB.addCallback(StateDatabase::BZDB_MAXLOD, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_WORLDSIZE, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_RADARLIMIT, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_GRAVITY, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_TANKWIDTH, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_TANKLENGTH, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_TANKHEIGHT, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_TANKSPEED, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_FLAGRADIUS, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_FLAGPOLESIZE, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_FLAGPOLEWIDTH, serverCallback, NULL);

  maxLOD = BZDB.eval(StateDatabase::BZDB_MAXLOD);
  worldSize = BZDB.eval(StateDatabase::BZDB_WORLDSIZE);
  radarLimit = BZDB.eval(StateDatabase::BZDB_RADARLIMIT);
  gravity = BZDB.eval(StateDatabase::BZDB_GRAVITY);
  tankWidth = BZDB.eval(StateDatabase::BZDB_TANKWIDTH);
  tankLength = BZDB.eval(StateDatabase::BZDB_TANKLENGTH);
  tankHeight = BZDB.eval(StateDatabase::BZDB_TANKHEIGHT);
  tankSpeed = BZDB.eval(StateDatabase::BZDB_TANKSPEED);
  tankRadius = BZDB.eval(StateDatabase::BZDB_TANKRADIUS);
  flagRadius = BZDB.eval(StateDatabase::BZDB_FLAGRADIUS);
  flagPoleSize = BZDB.eval(StateDatabase::BZDB_FLAGPOLESIZE);
  flagPoleWidth = BZDB.eval(StateDatabase::BZDB_FLAGPOLEWIDTH);

  update();
}

void BZDBCache::clientCallback(const std::string& name, void *)
{
  if (name == "blend")
    blend = BZDB.isTrue("blend");
  else if (name == "displayMainFlags")
    displayMainFlags = BZDB.isTrue("displayMainFlags");
  else if (name == "texture")
    texture = BZDB.isTrue("texture");
  else if (name == "shadows")
    shadows = BZDB.isTrue("shadows");
  else if (name == "zbuffer")
    zbuffer = BZDB.isTrue("zbuffer");
  else if (name == "tesselation")
    tesselation = BZDB.isTrue("tesselation");
  else if (name == "lighting")
    lighting = BZDB.isTrue("lighting");
  else if (name == "smooth")
    smooth = BZDB.isTrue("smooth");
  else if (name == "colorful")
    colorful = BZDB.isTrue("colorful");
  else if (name == "radarStyle")
    radarStyle = BZDB.evalInt("radarStyle");
  else if (name == "animatedTreads")
    animatedTreads = BZDB.isTrue("animatedTreads");
  else if (name == "leadingShotLine")
    leadingShotLine = BZDB.isTrue("leadingShotLine");
  else if (name == "flagChunks")
    flagChunks = BZDB.evalInt("flagChunks");
  else if (name == "pulseRate")
    pulseRate = BZDB.eval("pulseRate");
  else if (name == "pulseDepth")
    pulseDepth = BZDB.eval("pulseDepth");
  else if (name == "showCollisionGrid")
    showCollisionGrid = BZDB.isTrue("showCollisionGrid");
  else if (name == "showCullingGrid")
    showCullingGrid = BZDB.isTrue("showCullingGrid");
}

void BZDBCache::serverCallback(const std::string& name, void *)
{
  if (name == StateDatabase::BZDB_MAXLOD) {
    maxLOD = BZDB.eval(StateDatabase::BZDB_MAXLOD);
  }
  if (name == StateDatabase::BZDB_WORLDSIZE) {
    worldSize = BZDB.eval(StateDatabase::BZDB_WORLDSIZE);
  }
  if (name == StateDatabase::BZDB_RADARLIMIT) {
    radarLimit = BZDB.eval(StateDatabase::BZDB_RADARLIMIT);
  }
  if (name == StateDatabase::BZDB_GRAVITY) {
    gravity = BZDB.eval(StateDatabase::BZDB_GRAVITY);
  }
  else if (name == StateDatabase::BZDB_TANKWIDTH) {
    tankWidth = BZDB.eval(StateDatabase::BZDB_TANKWIDTH);
  }
  else if (name == StateDatabase::BZDB_TANKLENGTH) {
    tankLength = BZDB.eval(StateDatabase::BZDB_TANKLENGTH);
  }
  else if (name == StateDatabase::BZDB_TANKHEIGHT) {
    tankHeight = BZDB.eval(StateDatabase::BZDB_TANKHEIGHT);
  }
  else if (name == StateDatabase::BZDB_TANKSPEED) {
    tankSpeed = BZDB.eval(StateDatabase::BZDB_TANKSPEED);
  }
// Why only in update() ?
//  else if (name == StateDatabase::BZDB_FLAGRADIUS) {
//    flagRadius = BZDB.eval(StateDatabase::BZDB_FLAGRADIUS);
//  }
  else if (name == StateDatabase::BZDB_FLAGPOLESIZE) {
    flagPoleSize = BZDB.eval(StateDatabase::BZDB_FLAGPOLESIZE);
  }
  else if (name == StateDatabase::BZDB_FLAGPOLEWIDTH) {
    flagPoleWidth = BZDB.eval(StateDatabase::BZDB_FLAGPOLEWIDTH);
  }
}

void BZDBCache::update() {
  tankRadius = BZDB.eval(StateDatabase::BZDB_TANKRADIUS);
  linedRadarShots = static_cast<int>(BZDB.eval("linedradarshots"));
  sizedRadarShots = static_cast<int>(BZDB.eval("sizedradarshots"));
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<commit_msg>Interface header is the first, on cxx files<commit_after>/* bzflag
 * Copyright (c) 1993 - 2005 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */

#ifdef _MSC_VER
#pragma warning(4: 4786)
#endif

// interface header
#include "BZDBCache.h"

bool  BZDBCache::displayMainFlags;
bool  BZDBCache::blend;
bool  BZDBCache::texture;
bool  BZDBCache::shadows;
bool  BZDBCache::zbuffer;
bool  BZDBCache::tesselation;
bool  BZDBCache::lighting;
bool  BZDBCache::smooth;
bool  BZDBCache::colorful;
bool  BZDBCache::animatedTreads;
bool  BZDBCache::leadingShotLine;
int   BZDBCache::radarStyle;
int   BZDBCache::linedRadarShots;
int   BZDBCache::sizedRadarShots;
int   BZDBCache::flagChunks;
float BZDBCache::pulseRate;
float BZDBCache::pulseDepth;
bool  BZDBCache::showCollisionGrid;
bool  BZDBCache::showCullingGrid;

float BZDBCache::worldSize;
float BZDBCache::radarLimit;
float BZDBCache::gravity;
float BZDBCache::tankWidth;
float BZDBCache::tankLength;
float BZDBCache::tankHeight;
float BZDBCache::tankSpeed;
float BZDBCache::tankRadius;
float BZDBCache::flagRadius;
float BZDBCache::flagPoleSize;
float BZDBCache::flagPoleWidth;
float BZDBCache::maxLOD;

void BZDBCache::init()
{
  BZDB.addCallback("displayMainFlags", clientCallback, NULL);
  BZDB.addCallback("radarStyle", clientCallback, NULL);
  BZDB.addCallback("blend", clientCallback, NULL);
  BZDB.addCallback("texture", clientCallback, NULL);
  BZDB.addCallback("shadows", clientCallback, NULL);
  BZDB.addCallback("zbuffer", clientCallback, NULL);
  BZDB.addCallback("tesselation", clientCallback, NULL);
  BZDB.addCallback("lighting", clientCallback, NULL);
  BZDB.addCallback("smooth", clientCallback, NULL);
  BZDB.addCallback("colorful", clientCallback, NULL);
  BZDB.addCallback("animatedTreads", clientCallback, NULL);
  BZDB.addCallback("leadingShotLine", clientCallback, NULL);
  BZDB.addCallback("flagChunks", clientCallback, NULL);
  BZDB.addCallback("pulseRate", clientCallback, NULL);
  BZDB.addCallback("pulseDepth", clientCallback, NULL);
  BZDB.addCallback("showCollisionGrid", clientCallback, NULL);
  BZDB.addCallback("showCullingGrid", clientCallback, NULL);

  BZDB.addCallback(StateDatabase::BZDB_MAXLOD, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_WORLDSIZE, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_RADARLIMIT, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_GRAVITY, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_TANKWIDTH, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_TANKLENGTH, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_TANKHEIGHT, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_TANKSPEED, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_FLAGRADIUS, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_FLAGPOLESIZE, serverCallback, NULL);
  BZDB.addCallback(StateDatabase::BZDB_FLAGPOLEWIDTH, serverCallback, NULL);

  maxLOD = BZDB.eval(StateDatabase::BZDB_MAXLOD);
  worldSize = BZDB.eval(StateDatabase::BZDB_WORLDSIZE);
  radarLimit = BZDB.eval(StateDatabase::BZDB_RADARLIMIT);
  gravity = BZDB.eval(StateDatabase::BZDB_GRAVITY);
  tankWidth = BZDB.eval(StateDatabase::BZDB_TANKWIDTH);
  tankLength = BZDB.eval(StateDatabase::BZDB_TANKLENGTH);
  tankHeight = BZDB.eval(StateDatabase::BZDB_TANKHEIGHT);
  tankSpeed = BZDB.eval(StateDatabase::BZDB_TANKSPEED);
  tankRadius = BZDB.eval(StateDatabase::BZDB_TANKRADIUS);
  flagRadius = BZDB.eval(StateDatabase::BZDB_FLAGRADIUS);
  flagPoleSize = BZDB.eval(StateDatabase::BZDB_FLAGPOLESIZE);
  flagPoleWidth = BZDB.eval(StateDatabase::BZDB_FLAGPOLEWIDTH);

  update();
}

void BZDBCache::clientCallback(const std::string& name, void *)
{
  if (name == "blend")
    blend = BZDB.isTrue("blend");
  else if (name == "displayMainFlags")
    displayMainFlags = BZDB.isTrue("displayMainFlags");
  else if (name == "texture")
    texture = BZDB.isTrue("texture");
  else if (name == "shadows")
    shadows = BZDB.isTrue("shadows");
  else if (name == "zbuffer")
    zbuffer = BZDB.isTrue("zbuffer");
  else if (name == "tesselation")
    tesselation = BZDB.isTrue("tesselation");
  else if (name == "lighting")
    lighting = BZDB.isTrue("lighting");
  else if (name == "smooth")
    smooth = BZDB.isTrue("smooth");
  else if (name == "colorful")
    colorful = BZDB.isTrue("colorful");
  else if (name == "radarStyle")
    radarStyle = BZDB.evalInt("radarStyle");
  else if (name == "animatedTreads")
    animatedTreads = BZDB.isTrue("animatedTreads");
  else if (name == "leadingShotLine")
    leadingShotLine = BZDB.isTrue("leadingShotLine");
  else if (name == "flagChunks")
    flagChunks = BZDB.evalInt("flagChunks");
  else if (name == "pulseRate")
    pulseRate = BZDB.eval("pulseRate");
  else if (name == "pulseDepth")
    pulseDepth = BZDB.eval("pulseDepth");
  else if (name == "showCollisionGrid")
    showCollisionGrid = BZDB.isTrue("showCollisionGrid");
  else if (name == "showCullingGrid")
    showCullingGrid = BZDB.isTrue("showCullingGrid");
}

void BZDBCache::serverCallback(const std::string& name, void *)
{
  if (name == StateDatabase::BZDB_MAXLOD) {
    maxLOD = BZDB.eval(StateDatabase::BZDB_MAXLOD);
  }
  if (name == StateDatabase::BZDB_WORLDSIZE) {
    worldSize = BZDB.eval(StateDatabase::BZDB_WORLDSIZE);
  }
  if (name == StateDatabase::BZDB_RADARLIMIT) {
    radarLimit = BZDB.eval(StateDatabase::BZDB_RADARLIMIT);
  }
  if (name == StateDatabase::BZDB_GRAVITY) {
    gravity = BZDB.eval(StateDatabase::BZDB_GRAVITY);
  }
  else if (name == StateDatabase::BZDB_TANKWIDTH) {
    tankWidth = BZDB.eval(StateDatabase::BZDB_TANKWIDTH);
  }
  else if (name == StateDatabase::BZDB_TANKLENGTH) {
    tankLength = BZDB.eval(StateDatabase::BZDB_TANKLENGTH);
  }
  else if (name == StateDatabase::BZDB_TANKHEIGHT) {
    tankHeight = BZDB.eval(StateDatabase::BZDB_TANKHEIGHT);
  }
  else if (name == StateDatabase::BZDB_TANKSPEED) {
    tankSpeed = BZDB.eval(StateDatabase::BZDB_TANKSPEED);
  }
// Why only in update() ?
//  else if (name == StateDatabase::BZDB_FLAGRADIUS) {
//    flagRadius = BZDB.eval(StateDatabase::BZDB_FLAGRADIUS);
//  }
  else if (name == StateDatabase::BZDB_FLAGPOLESIZE) {
    flagPoleSize = BZDB.eval(StateDatabase::BZDB_FLAGPOLESIZE);
  }
  else if (name == StateDatabase::BZDB_FLAGPOLEWIDTH) {
    flagPoleWidth = BZDB.eval(StateDatabase::BZDB_FLAGPOLEWIDTH);
  }
}

void BZDBCache::update() {
  tankRadius = BZDB.eval(StateDatabase::BZDB_TANKRADIUS);
  linedRadarShots = static_cast<int>(BZDB.eval("linedradarshots"));
  sizedRadarShots = static_cast<int>(BZDB.eval("sizedradarshots"));
}

// Local Variables: ***
// mode: C++ ***
// tab-width: 8 ***
// c-basic-offset: 2 ***
// indent-tabs-mode: t ***
// End: ***
// ex: shiftwidth=2 tabstop=8
<|endoftext|>


<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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 "condor_common.h"
#define KBDD
#ifdef WIN32
#include "condor_daemon_core.h"
#include "condor_debug.h"
#include "condor_uid.h"
#else
#include "XInterface.h"
#endif

#include "my_hostname.h"
#include "condor_query.h"
#include "daemon.h"
#include "subsystem_info.h"

#ifdef WIN32
#include <windows.h>
#else
#include <utmp.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <rpc/types.h>
#include <X11/Xlib.h>

XInterface *xinter;
#endif

DECL_SUBSYSTEM( "KBDD", SUBSYSTEM_TYPE_DAEMON );

bool
update_startd()
{
    static SafeSock ssock;
	static bool first_time = true;
	static Daemon startd( DT_STARTD );
	if( first_time ) {
		if( ! startd.locate() ) {
			dprintf( D_ALWAYS, "Can't locate startd, aborting (%s)\n",
					 startd.error() );
			return false;
		}
		if( !ssock.connect(startd.addr(), 0) ) {
			dprintf( D_ALWAYS, "Can't connect to startd at: %s, "
					 "aborting\n", startd.addr() );
			return false;
		}
		first_time = false;
	}
	if( !startd.sendCommand(X_EVENT_NOTIFICATION, &ssock, 3) ) {
		dprintf( D_ALWAYS, "Can't send X_EVENT_NOTIFICATION command "
				 "to startd at: %s, aborting\n", startd.addr() );
		return false;
	}
	dprintf( D_FULLDEBUG, "Sent update to startd at: %s\n", startd.addr() );
	return true;
}

void
PollActivity()
{
#ifdef WIN32
	LASTINPUTINFO lii;
	static POINT previous_pos = { 0, 0 };
	static DWORD previous_input_tick = 0;

	lii.cbSize = sizeof(LASTINPUTINFO);
	lii.dwTime = 0;

	if ( !GetLastInputInfo(&lii) ) {
		dprintf(D_ALWAYS, "PollActivity: GetLastInputInfo()"
			" failed with err=%d\n", GetLastError());
	}
	else
	{

		//Check if there has been new keyboard input since the last check.
		if(lii.dwTime > previous_input_tick)
		{
			previous_input_tick = lii.dwTime;
			update_startd();
		}

		return;
	}

	//If no change to keyboard input, check if mouse has been moved.
	CURSORINFO cursor_inf;
	cursor_inf.cbSize = sizeof(CURSORINFO);
	if (!GetCursorInfo(&cursor_inf))
	{
		dprintf(D_ALWAYS,"GetCursorInfo() failed (err=%li)\n",
		GetLastError());
	}
	else
	{
		if ((cursor_inf.ptScreenPos.x != previous_pos.x) ||
			(cursor_inf.ptScreenPos.y != previous_pos.y))
		{
			// the mouse has moved!
			// stash new position
			previous_pos.x = cursor_inf.ptScreenPos.x;
			previous_pos.y = cursor_inf.ptScreenPos.y;
			previous_input_tick = GetTickCount();
			update_startd();
		}
	}

	return;

#else
    if(xinter != NULL)
    {
	if(xinter->CheckActivity())
	{
	    update_startd();
	}
    }
#endif
}

int
main_shutdown_graceful()
{
#ifndef WIN32
    delete xinter;
#endif
    DC_Exit(EXIT_SUCCESS);
	return TRUE;
}

int
main_shutdown_fast()
{
	DC_Exit(EXIT_SUCCESS);
	return TRUE;
}

int
main_config( bool is_full )
{
    return TRUE;
}

int
main_init(int, char *[])
{
    int id;
#ifndef WIN32
	xinter = NULL;
	xinter = new XInterface(id);
#endif
    //Poll for X activity every second.
    id = daemonCore->Register_Timer(5, 5, PollActivity, "PollActivity");

    return TRUE;
}

void
main_pre_dc_init( int, char*[] )
{
}

void
main_pre_command_sock_init( )
{
}

#ifdef WIN32
int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
	// cons up a "standard" argv for dc_main.
	char **parameters = (char**)malloc(sizeof(char*)*2);
	parameters[0] = "condor_kbdd";
	parameters[1] = NULL;
	dc_main(1, parameters);

	// dc_main should exit() so we probably never get here.
	return 0;
}
#endif

<commit_msg>Fix use of uninitialized variable causing kbdd to go haywire and chew up 100% CPU.  Bug introduced in 7.4.0 #714.  Bug identified in #1337.<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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 "condor_common.h"
#define KBDD
#ifdef WIN32
#include "condor_daemon_core.h"
#include "condor_debug.h"
#include "condor_uid.h"
#else
#include "XInterface.h"
#endif

#include "my_hostname.h"
#include "condor_query.h"
#include "daemon.h"
#include "subsystem_info.h"

#ifdef WIN32
#include <windows.h>
#else
#include <utmp.h>
#include <sys/file.h>
#include <netinet/in.h>
#include <rpc/types.h>
#include <X11/Xlib.h>

XInterface *xinter = NULL;
#endif

DECL_SUBSYSTEM( "KBDD", SUBSYSTEM_TYPE_DAEMON );

bool
update_startd()
{
    static SafeSock ssock;
	static bool first_time = true;
	static Daemon startd( DT_STARTD );
	if( first_time ) {
		if( ! startd.locate() ) {
			dprintf( D_ALWAYS, "Can't locate startd, aborting (%s)\n",
					 startd.error() );
			return false;
		}
		if( !ssock.connect(startd.addr(), 0) ) {
			dprintf( D_ALWAYS, "Can't connect to startd at: %s, "
					 "aborting\n", startd.addr() );
			return false;
		}
		first_time = false;
	}
	if( !startd.sendCommand(X_EVENT_NOTIFICATION, &ssock, 3) ) {
		dprintf( D_ALWAYS, "Can't send X_EVENT_NOTIFICATION command "
				 "to startd at: %s, aborting\n", startd.addr() );
		return false;
	}
	dprintf( D_FULLDEBUG, "Sent update to startd at: %s\n", startd.addr() );
	return true;
}

void
PollActivity()
{
#ifdef WIN32
	LASTINPUTINFO lii;
	static POINT previous_pos = { 0, 0 };
	static DWORD previous_input_tick = 0;

	lii.cbSize = sizeof(LASTINPUTINFO);
	lii.dwTime = 0;

	if ( !GetLastInputInfo(&lii) ) {
		dprintf(D_ALWAYS, "PollActivity: GetLastInputInfo()"
			" failed with err=%d\n", GetLastError());
	}
	else
	{

		//Check if there has been new keyboard input since the last check.
		if(lii.dwTime > previous_input_tick)
		{
			previous_input_tick = lii.dwTime;
			update_startd();
		}

		return;
	}

	//If no change to keyboard input, check if mouse has been moved.
	CURSORINFO cursor_inf;
	cursor_inf.cbSize = sizeof(CURSORINFO);
	if (!GetCursorInfo(&cursor_inf))
	{
		dprintf(D_ALWAYS,"GetCursorInfo() failed (err=%li)\n",
		GetLastError());
	}
	else
	{
		if ((cursor_inf.ptScreenPos.x != previous_pos.x) ||
			(cursor_inf.ptScreenPos.y != previous_pos.y))
		{
			// the mouse has moved!
			// stash new position
			previous_pos.x = cursor_inf.ptScreenPos.x;
			previous_pos.y = cursor_inf.ptScreenPos.y;
			previous_input_tick = GetTickCount();
			update_startd();
		}
	}

	return;

#else
    if(xinter != NULL)
    {
	if(xinter->CheckActivity())
	{
	    update_startd();
	}
    }
#endif
}

int
main_shutdown_graceful()
{
#ifndef WIN32
    delete xinter;
#endif
    DC_Exit(EXIT_SUCCESS);
	return TRUE;
}

int
main_shutdown_fast()
{
	DC_Exit(EXIT_SUCCESS);
	return TRUE;
}

int
main_config( bool is_full )
{
    return TRUE;
}

int
main_init(int, char *[])
{
#ifndef WIN32
	xinter = NULL;
#endif
    //Poll for X activity every second.
    int id = daemonCore->Register_Timer(5, 5, PollActivity, "PollActivity");
#ifndef WIN32
	xinter = new XInterface(id);
#endif

    return TRUE;
}

void
main_pre_dc_init( int, char*[] )
{
}

void
main_pre_command_sock_init( )
{
}

#ifdef WIN32
int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
	// cons up a "standard" argv for dc_main.
	char **parameters = (char**)malloc(sizeof(char*)*2);
	parameters[0] = "condor_kbdd";
	parameters[1] = NULL;
	dc_main(1, parameters);

	// dc_main should exit() so we probably never get here.
	return 0;
}
#endif

<|endoftext|>


<commit_before>/*  -*- mode: C++; c-file-style: "gnu" -*-

    This file is part of kdepim.
    Copyright (c) 2004 KDEPIM developers

    KMail is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License, version 2, as
    published by the Free Software Foundation.

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "email.h"
#include <kdebug.h>

//-----------------------------------------------------------------------------
QStringList KPIM::splitEmailAddrList(const QString& aStr)
{
  // Features:
  // - always ignores quoted characters
  // - ignores everything (including parentheses and commas)
  //   inside quoted strings
  // - supports nested comments
  // - ignores everything (including double quotes and commas)
  //   inside comments

  QStringList list;

  if (aStr.isEmpty())
    return list;

  QString addr;
  uint addrstart = 0;
  int commentlevel = 0;
  bool insidequote = false;

  for (uint index=0; index<aStr.length(); index++) {
    // the following conversion to latin1 is o.k. because
    // we can safely ignore all non-latin1 characters
    switch (aStr[index].latin1()) {
    case '"' : // start or end of quoted string
      if (commentlevel == 0)
        insidequote = !insidequote;
      break;
    case '(' : // start of comment
      if (!insidequote)
        commentlevel++;
      break;
    case ')' : // end of comment
      if (!insidequote) {
        if (commentlevel > 0)
          commentlevel--;
        else {
          kdDebug(5300) << "Error in address splitting: Unmatched ')'"
                        << endl;
          return list;
        }
      }
      break;
    case '\\' : // quoted character
      index++; // ignore the quoted character
      break;
    case ',' :
      if (!insidequote && (commentlevel == 0)) {
        addr = aStr.mid(addrstart, index-addrstart);
        if (!addr.isEmpty())
          list += addr.simplifyWhiteSpace();
        addrstart = index+1;
      }
      break;
    }
  }
  // append the last address to the list
  if (!insidequote && (commentlevel == 0)) {
    addr = aStr.mid(addrstart, aStr.length()-addrstart);
    if (!addr.isEmpty())
      list += addr.simplifyWhiteSpace();
  }
  else
    kdDebug(5300) << "Error in address splitting: "
                  << "Unexpected end of address list"
                  << endl;

  return list;
}

//-----------------------------------------------------------------------------
QCString KPIM::getEmailAddr(const QString& aStr)
{
  int a, i, j, len, found = 0;
  QChar c;
  // Find the '@' in the email address:
  a = aStr.find('@');
  if (a<0) return aStr.latin1();
  // Loop backwards until we find '<', '(', ' ', or beginning of string.
  for (i = a - 1; i >= 0; i--) {
    c = aStr[i];
    if (c == '<' || c == '(' || c == ' ') found = 1;
    if (found) break;
  }
  // Reset found for next loop.
  found = 0;
  // Loop forwards until we find '>', ')', ' ', or end of string.
  for (j = a + 1; j < (int)aStr.length(); j++) {
    c = aStr[j];
    if (c == '>' || c == ')' || c == ' ') found = 1;
    if (found) break;
  }
  // Calculate the length and return the result.
  len = j - (i + 1);
  return aStr.mid(i+1,len).latin1();
}

//static:
bool KPIM::getNameAndMail(const QString& aStr, QString& name, QString& mail)
{
  name = QString::null;
  mail = QString::null;

  const int len=aStr.length();

  bool bInComment;
  int i=0, iAd=0, iMailStart=0, iMailEnd=0;
  QChar c;

  // Find the '@' of the email address
  // skipping all '@' inside "(...)" comments:
  bInComment = false;
  while( i < len ){
    c = aStr[i];
    if( !bInComment ){
      if( '(' == c ){
        bInComment = true;
      }else{
        if( '@' == c ){
          iAd = i;
          break; // found it
        }
      }
    }else{
      if( ')' == c ){
        bInComment = false;
      }
    }
    ++i;
  }

  if( !iAd ){
    // We suppose the user is typing the string manually and just
    // has not finished typing the mail address part.
    // So we take everything that's left of the '<' as name and the rest as mail
    for( i = 0; len > i; ++i ) {
      c = aStr[i];
      if( '<' != c )
        name.append( c );
      else
        break;
    }
    mail = aStr.mid( i+1 );

  }else{

    // Loop backwards until we find the start of the string
    // or a ',' outside of a comment.
    bInComment = false;
    for( i = iAd-1; 0 <= i; --i ) {
      c = aStr[i];
      if( bInComment ){
        if( '(' == c ){
          if( !name.isEmpty() )
            name.prepend( ' ' );
          bInComment = false;
        }else{
          name.prepend( c ); // all comment stuff is part of the name
        }
      }else{
        // found the start of this addressee ?
        if( ',' == c )
          break;
        // stuff is before the leading '<' ?
        if( iMailStart ){
          name.prepend( c );
        }else{
          switch( c ){
            case '<':
              iMailStart = i;
              break;
            case ')':
              if( !name.isEmpty() )
                name.prepend( ' ' );
              bInComment = true;
              break;
            default:
              if( ' ' != c )
                mail.prepend( c );
          }
        }
      }
    }

    name = name.simplifyWhiteSpace();
    mail = mail.simplifyWhiteSpace();

    if( mail.isEmpty() )
      return false;

    mail.append('@');

    // Loop forward until we find the end of the string
    // or a ',' outside of a comment.
    bInComment = false;
    for( i = iAd+1; len > i; ++i ) {
      c = aStr[i];
      if( bInComment ){
        if( ')' == c ){
          if( !name.isEmpty() )
            name.append( ' ' );
          bInComment = false;
        }else{
          name.append( c ); // all comment stuff is part of the name
        }
      }else{
        // found the end of this addressee ?
        if( ',' == c )
          break;
        // stuff is behind the trailing '<' ?
        if( iMailEnd ){
          name.append( c );
        }else{
          switch( c ){
            case '>':
              iMailEnd = i;
              break;
            case '(':
              if( !name.isEmpty() )
                name.append( ' ' );
              bInComment = true;
              break;
            default:
              if( ' ' != c )
                mail.append( c );
          }
        }
      }
    }
  }

  name = name.simplifyWhiteSpace();
  mail = mail.simplifyWhiteSpace();

  return ! (name.isEmpty() || mail.isEmpty());
}
<commit_msg>Bugfix: ',' commata inside a '"' .. '"' quoted text part were erroneously interpreted as address-dividing commata.  So the address    "Doe, Joe" <joe.doe@host>    made KPIM::getNameAndMail(..) return the following as name part:   Joe"     After this bugfix the returned text is:   "Doe, Joe"<commit_after>/*  -*- mode: C++; c-file-style: "gnu" -*-

    This file is part of kdepim.
    Copyright (c) 2004 KDEPIM developers

    KMail is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License, version 2, as
    published by the Free Software Foundation.

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

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include "email.h"
#include <kdebug.h>

//-----------------------------------------------------------------------------
QStringList KPIM::splitEmailAddrList(const QString& aStr)
{
  // Features:
  // - always ignores quoted characters
  // - ignores everything (including parentheses and commas)
  //   inside quoted strings
  // - supports nested comments
  // - ignores everything (including double quotes and commas)
  //   inside comments

  QStringList list;

  if (aStr.isEmpty())
    return list;

  QString addr;
  uint addrstart = 0;
  int commentlevel = 0;
  bool insidequote = false;

  for (uint index=0; index<aStr.length(); index++) {
    // the following conversion to latin1 is o.k. because
    // we can safely ignore all non-latin1 characters
    switch (aStr[index].latin1()) {
    case '"' : // start or end of quoted string
      if (commentlevel == 0)
        insidequote = !insidequote;
      break;
    case '(' : // start of comment
      if (!insidequote)
        commentlevel++;
      break;
    case ')' : // end of comment
      if (!insidequote) {
        if (commentlevel > 0)
          commentlevel--;
        else {
          kdDebug(5300) << "Error in address splitting: Unmatched ')'"
                        << endl;
          return list;
        }
      }
      break;
    case '\\' : // quoted character
      index++; // ignore the quoted character
      break;
    case ',' :
      if (!insidequote && (commentlevel == 0)) {
        addr = aStr.mid(addrstart, index-addrstart);
        if (!addr.isEmpty())
          list += addr.simplifyWhiteSpace();
        addrstart = index+1;
      }
      break;
    }
  }
  // append the last address to the list
  if (!insidequote && (commentlevel == 0)) {
    addr = aStr.mid(addrstart, aStr.length()-addrstart);
    if (!addr.isEmpty())
      list += addr.simplifyWhiteSpace();
  }
  else
    kdDebug(5300) << "Error in address splitting: "
                  << "Unexpected end of address list"
                  << endl;

  return list;
}

//-----------------------------------------------------------------------------
QCString KPIM::getEmailAddr(const QString& aStr)
{
  int a, i, j, len, found = 0;
  QChar c;
  // Find the '@' in the email address:
  a = aStr.find('@');
  if (a<0) return aStr.latin1();
  // Loop backwards until we find '<', '(', ' ', or beginning of string.
  for (i = a - 1; i >= 0; i--) {
    c = aStr[i];
    if (c == '<' || c == '(' || c == ' ') found = 1;
    if (found) break;
  }
  // Reset found for next loop.
  found = 0;
  // Loop forwards until we find '>', ')', ' ', or end of string.
  for (j = a + 1; j < (int)aStr.length(); j++) {
    c = aStr[j];
    if (c == '>' || c == ')' || c == ' ') found = 1;
    if (found) break;
  }
  // Calculate the length and return the result.
  len = j - (i + 1);
  return aStr.mid(i+1,len).latin1();
}

//static:
bool KPIM::getNameAndMail(const QString& aStr, QString& name, QString& mail)
{
  name = QString::null;
  mail = QString::null;

  const int len=aStr.length();
  const char cQuotes = '"';

  bool bInComment, bInQuotesOutsideOfEmail;
  int i=0, iAd=0, iMailStart=0, iMailEnd=0;
  QChar c;

  // Find the '@' of the email address
  // skipping all '@' inside "(...)" comments:
  bInComment = false;
  while( i < len ){
    c = aStr[i];
    if( !bInComment ){
      if( '(' == c ){
        bInComment = true;
      }else{
        if( '@' == c ){
          iAd = i;
          break; // found it
        }
      }
    }else{
      if( ')' == c ){
        bInComment = false;
      }
    }
    ++i;
  }

  if( !iAd ){
    // We suppose the user is typing the string manually and just
    // has not finished typing the mail address part.
    // So we take everything that's left of the '<' as name and the rest as mail
    for( i = 0; len > i; ++i ) {
      c = aStr[i];
      if( '<' != c )
        name.append( c );
      else
        break;
    }
    mail = aStr.mid( i+1 );

  }else{

    // Loop backwards until we find the start of the string
    // or a ',' that is outside of a comment
    //          and outside of quoted text before the leading '<'.
    bInComment = false;
    bInQuotesOutsideOfEmail = false;
    for( i = iAd-1; 0 <= i; --i ) {
      c = aStr[i];
      if( bInComment ){
        if( '(' == c ){
          if( !name.isEmpty() )
            name.prepend( ' ' );
          bInComment = false;
        }else{
          name.prepend( c ); // all comment stuff is part of the name
        }
      }else if( bInQuotesOutsideOfEmail ){
        if( cQuotes == c )
          bInQuotesOutsideOfEmail = false;
        name.prepend( c );
      }else{
        // found the start of this addressee ?
        if( ',' == c )
          break;
        // stuff is before the leading '<' ?
        if( iMailStart ){
          if( cQuotes == c )
            bInQuotesOutsideOfEmail = true; // end of quoted text found
          name.prepend( c );
        }else{
          switch( c ){
            case '<':
              iMailStart = i;
              break;
            case ')':
              if( !name.isEmpty() )
                name.prepend( ' ' );
              bInComment = true;
              break;
            default:
              if( ' ' != c )
                mail.prepend( c );
          }
        }
      }
    }

    name = name.simplifyWhiteSpace();
    mail = mail.simplifyWhiteSpace();

    if( mail.isEmpty() )
      return false;

    mail.append('@');

    // Loop forward until we find the end of the string
    // or a ',' that is outside of a comment
    //          and outside of quoted text behind the trailing '>'.
    bInComment = false;
    bInQuotesOutsideOfEmail = false;
    for( i = iAd+1; len > i; ++i ) {
      c = aStr[i];
      if( bInComment ){
        if( ')' == c ){
          if( !name.isEmpty() )
            name.append( ' ' );
          bInComment = false;
        }else{
          name.append( c ); // all comment stuff is part of the name
        }
      }else if( bInQuotesOutsideOfEmail ){
        if( cQuotes == c )
          bInQuotesOutsideOfEmail = false;
        name.append( c );
      }else{
        // found the end of this addressee ?
        if( ',' == c )
          break;
        // stuff is behind the trailing '>' ?
        if( iMailEnd ){
          if( cQuotes == c )
            bInQuotesOutsideOfEmail = true; // start of quoted text found
          name.append( c );
        }else{
          switch( c ){
            case '>':
              iMailEnd = i;
              break;
            case '(':
              if( !name.isEmpty() )
                name.append( ' ' );
              bInComment = true;
              break;
            default:
              if( ' ' != c )
                mail.append( c );
          }
        }
      }
    }
  }

  name = name.simplifyWhiteSpace();
  mail = mail.simplifyWhiteSpace();

  return ! (name.isEmpty() || mail.isEmpty());
}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef SOL_PROXY_HPP
#define SOL_PROXY_HPP

#include "traits.hpp"
#include "object.hpp"
#include "function.hpp"
#include "protected_function.hpp"
#include "proxy_base.hpp"

namespace sol {
template<typename Table, typename Key>
struct proxy : public proxy_base<proxy<Table, Key>> {
private:
    typedef meta::If<meta::is_specialization_of<Key, std::tuple>, Key, std::tuple<meta::If<std::is_array<meta::Unqualified<Key>>, Key&, meta::Unqualified<Key>>>> key_type;

    template<typename T, std::size_t... I>
    decltype(auto) tuple_get(std::index_sequence<I...>) const {
        return tbl.template traverse_get<T>( std::get<I>(key)... );
    }

    template<std::size_t... I, typename T>
    void tuple_set(std::index_sequence<I...>, T&& value) const {
        tbl.traverse_set( std::get<I>(key)..., std::forward<T>(value) );
    }

public:
    Table tbl;
    key_type key;

    template<typename T>
    proxy(Table table, T&& key) : tbl(table), key(std::forward<T>(key)) {}

    template<typename T>
    proxy& set(T&& item) {
        tuple_set( std::make_index_sequence<std::tuple_size<meta::Unqualified<key_type>>::value>(), std::forward<T>(item) );
        return *this;
    }

    template<typename... Args>
    proxy& set_function(Args&&... args) {
        tbl.set_function(key, std::forward<Args>(args)...);
        return *this;
    }

    template<typename U, meta::EnableIf<meta::Function<meta::Unqualified<U>>> = 0>
    proxy& operator=(U&& other) {
        return set_function(std::forward<U>(other));
    }

    template<typename U, meta::DisableIf<meta::Function<meta::Unqualified<U>>> = 0>
    proxy& operator=(U&& other) {
        return set(std::forward<U>(other));
    }

    template<typename T>
    decltype(auto) get() const {
        return tuple_get<T>( std::make_index_sequence<std::tuple_size<meta::Unqualified<key_type>>::value>() );
    }

    template <typename K>
    decltype(auto) operator[](K&& k) const {
        auto keys = meta::tuplefy(key, std::forward<K>(k));
        return proxy<Table, decltype(keys)>(tbl, std::move(keys));
    }

    template<typename... Ret, typename... Args>
    decltype(auto) call(Args&&... args) {
        return get<function>().template call<Ret...>(std::forward<Args>(args)...);
    }

    template<typename... Args>
    decltype(auto) operator()(Args&&... args) {
        return call<>(std::forward<Args>(args)...);
    }

    bool valid () const {
        auto p = stack::probe_get_field<std::is_same<meta::Unqualified<Table>, global_table>::value>(tbl.lua_state(), key);
	   lua_pop(tbl.lua_state(), p.levels);
	   return p;
    }
};

template<typename Table, typename Key, typename T>
inline bool operator==(T&& left, const proxy<Table, Key>& right) {
    return left == right.template get<std::decay_t<T>>();
}

template<typename Table, typename Key, typename T>
inline bool operator==(const proxy<Table, Key>& right, T&& left) {
    return right.template get<std::decay_t<T>>() == left;
}

template<typename Table, typename Key, typename T>
inline bool operator!=(T&& left, const proxy<Table, Key>& right) {
    return right.template get<std::decay_t<T>>() != left;
}

template<typename Table, typename Key, typename T>
inline bool operator!=(const proxy<Table, Key>& right, T&& left) {
    return right.template get<std::decay_t<T>>() != left;
}

template<typename Table, typename Key>
inline bool operator==(nil_t left, const proxy<Table, Key>& right) {
    return !right.valid();
}

template<typename Table, typename Key>
inline bool operator==(const proxy<Table, Key>& right, nil_t) {
    return !right.valid();
}

template<typename Table, typename Key>
inline bool operator!=(nil_t, const proxy<Table, Key>& right) {
    return right.valid();
}

template<typename Table, typename Key>
inline bool operator!=(const proxy<Table, Key>& right, nil_t) {
    return right.valid();
}

namespace stack {
template <typename Table, typename Key>
struct pusher<proxy<Table, Key>> {
    static int push (lua_State*, const proxy<Table, Key>& p) {
	   sol::reference r = p;
	   r.push();
        return 1;
    }
};
} // stack
} // sol

#endif // SOL_PROXY_HPP
<commit_msg>Off by one errors .-.<commit_after>// The MIT License (MIT)

// Copyright (c) 2013-2016 Rapptz, ThePhD and contributors

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef SOL_PROXY_HPP
#define SOL_PROXY_HPP

#include "traits.hpp"
#include "object.hpp"
#include "function.hpp"
#include "protected_function.hpp"
#include "proxy_base.hpp"

namespace sol {
template<typename Table, typename Key>
struct proxy : public proxy_base<proxy<Table, Key>> {
private:
    typedef meta::If<meta::is_specialization_of<Key, std::tuple>, Key, std::tuple<meta::If<std::is_array<meta::Unqualified<Key>>, Key&, meta::Unqualified<Key>>>> key_type;

    template<typename T, std::size_t... I>
    decltype(auto) tuple_get(std::index_sequence<I...>) const {
        return tbl.template traverse_get<T>( std::get<I>(key)... );
    }

    template<std::size_t... I, typename T>
    void tuple_set(std::index_sequence<I...>, T&& value) const {
        tbl.traverse_set( std::get<I>(key)..., std::forward<T>(value) );
    }

public:
    Table tbl;
    key_type key;

    template<typename T>
    proxy(Table table, T&& key) : tbl(table), key(std::forward<T>(key)) {}

    template<typename T>
    proxy& set(T&& item) {
        tuple_set( std::make_index_sequence<std::tuple_size<meta::Unqualified<key_type>>::value>(), std::forward<T>(item) );
        return *this;
    }

    template<typename... Args>
    proxy& set_function(Args&&... args) {
        tbl.set_function(key, std::forward<Args>(args)...);
        return *this;
    }

    template<typename U, meta::EnableIf<meta::Function<meta::Unqualified<U>>> = 0>
    proxy& operator=(U&& other) {
        return set_function(std::forward<U>(other));
    }

    template<typename U, meta::DisableIf<meta::Function<meta::Unqualified<U>>> = 0>
    proxy& operator=(U&& other) {
        return set(std::forward<U>(other));
    }

    template<typename T>
    decltype(auto) get() const {
        return tuple_get<T>( std::make_index_sequence<std::tuple_size<meta::Unqualified<key_type>>::value>() );
    }

    template <typename K>
    decltype(auto) operator[](K&& k) const {
        auto keys = meta::tuplefy(key, std::forward<K>(k));
        return proxy<Table, decltype(keys)>(tbl, std::move(keys));
    }

    template<typename... Ret, typename... Args>
    decltype(auto) call(Args&&... args) {
        return get<function>().template call<Ret...>(std::forward<Args>(args)...);
    }

    template<typename... Args>
    decltype(auto) operator()(Args&&... args) {
        return call<>(std::forward<Args>(args)...);
    }

    bool valid () const {
        auto p = stack::probe_get_field<std::is_same<meta::Unqualified<Table>, global_table>::value>(tbl.lua_state(), key);
	   lua_pop(tbl.lua_state(), p.levels);
	   return p;
    }
};

template<typename Table, typename Key, typename T>
inline bool operator==(T&& left, const proxy<Table, Key>& right) {
    return left == right.template get<std::decay_t<T>>();
}

template<typename Table, typename Key, typename T>
inline bool operator==(const proxy<Table, Key>& right, T&& left) {
    return right.template get<std::decay_t<T>>() == left;
}

template<typename Table, typename Key, typename T>
inline bool operator!=(T&& left, const proxy<Table, Key>& right) {
    return right.template get<std::decay_t<T>>() != left;
}

template<typename Table, typename Key, typename T>
inline bool operator!=(const proxy<Table, Key>& right, T&& left) {
    return right.template get<std::decay_t<T>>() != left;
}

template<typename Table, typename Key>
inline bool operator==(nil_t, const proxy<Table, Key>& right) {
    return !right.valid();
}

template<typename Table, typename Key>
inline bool operator==(const proxy<Table, Key>& right, nil_t) {
    return !right.valid();
}

template<typename Table, typename Key>
inline bool operator!=(nil_t, const proxy<Table, Key>& right) {
    return right.valid();
}

template<typename Table, typename Key>
inline bool operator!=(const proxy<Table, Key>& right, nil_t) {
    return right.valid();
}

namespace stack {
template <typename Table, typename Key>
struct pusher<proxy<Table, Key>> {
    static int push (lua_State*, const proxy<Table, Key>& p) {
	   sol::reference r = p;
	   r.push();
        return 1;
    }
};
} // stack
} // sol

#endif // SOL_PROXY_HPP
<|endoftext|>


<commit_before>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <iostream>
#include <fstream>
#include <iomanip>

#include <minizinc/model.hh>
#include <minizinc/parser.hh>
#include <minizinc/prettyprinter.hh>
#include <minizinc/typecheck.hh>
#include <minizinc/astexception.hh>
#include <minizinc/hash.hh>
#include <minizinc/eval_par.hh>
#include <minizinc/builtins.hh>
#include <minizinc/file_utils.hh>
#include <minizinc/timer.hh>

using namespace MiniZinc;
using namespace std;

std::string stoptime(Timer& timer) {
  std::ostringstream oss;
  oss << std::setprecision(0) << std::fixed << timer.ms() << " ms";
  return oss.str();
}

int main(int argc, char** argv) {
  Timer starttime;
  string filename;

  string flag_output_file;

  bool flag_output_comments = true;
  bool flag_output_flush = true;
  bool flag_output_time = false;
  string solfile;
  int flag_ignore_lines = 0;
  istream& solstream = cin;

  string solution_separator = "----------";
  string solution_comma     = "";
  string unsatisfiable_msg  = "=====UNSATISFIABLE=====";
  string unbounded_msg      = "=====UNBOUNDED=====";
  string unknown_msg        = "=====UNKNOWN=====";
  string search_complete_msg= "==========";

  vector<string> includePaths;
  string std_lib_dir;
  if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) {
    std_lib_dir = string(MZNSTDLIBDIR);
  }

  if (argc < 2)
    goto error;

  for (int i=1; i<argc; i++) {
    if (string(argv[i])==string("--version")) {
      std::cout << "NICTA MiniZinc solution printing tool, version "
      << MZN_VERSION_MAJOR << "." << MZN_VERSION_MINOR << "." << MZN_VERSION_PATCH << std::endl;
      std::cout << "Copyright (C) 2014, 2015 Monash University and NICTA" << std::endl;
      std::exit(EXIT_SUCCESS);
    }
    if (string(argv[i])==string("-h") || string(argv[i])==string("--help")) {
        goto error;
    } else if (string(argv[i])=="-o" || string(argv[i])=="--output-to-file") {
      i++;
      if (i==argc)
        goto error;
      flag_output_file = argv[i];
    } else if (string(argv[i])=="--stdlib-dir") {
      i++;
      if (i==argc)
        goto error;
      std_lib_dir = argv[i];
    } else if (string(argv[i])=="--no-flush-output") {
      flag_output_flush = false;
    } else if (string(argv[i])=="--no-output-comments") {
      flag_output_comments = false;
    } else if (string(argv[i])=="-i" ||
               string(argv[i])=="--ignore-lines" ||
               string(argv[i])=="--ignore-leading-lines") {
      ++i;
      if (i==argc)
        goto error;
      flag_ignore_lines = atoi(argv[i]);
    } else if (string(argv[i])=="--soln-sep" ||
               string(argv[i])=="--soln-separator" ||
               string(argv[i])=="--solution-separator") {
      ++i;
      if (i==argc)
        goto error;
      solution_separator = string(argv[i]);
    } else if (string(argv[i])=="--soln-comma" ||
               string(argv[i])=="--solution-comma") {
      ++i;
      if (i==argc)
        goto error;
      solution_comma = string(argv[i]);
    } else if (string(argv[i])=="--unsat-msg" ||
               string(argv[i])=="--unsatisfiable-msg") {
      ++i;
      if (i==argc)
        goto error;
      unsatisfiable_msg = string(argv[i]);
    } else if (string(argv[i])=="--unbounded-msg") {
      ++i;
      if (i==argc)
        goto error;
      unbounded_msg = string(argv[i]);
    } else if (string(argv[i])=="--unknown-msg") {
      ++i;
      if (i==argc)
        goto error;
      unknown_msg = string(argv[i]);
    } else if (string(argv[i])=="--search-complete-msg") {
      ++i;
      if (i==argc)
        goto error;
      search_complete_msg = string(argv[i]);
    } else if (string(argv[i])=="--output-time") {
      flag_output_time = true;
    } else {
      filename = argv[i++];
      if (filename.length()<=4 ||
          filename.substr(filename.length()-4,string::npos) != ".ozn") {
        std::cerr << "Invalid .ozn file " << filename << "." << std::endl;
        goto error;
      }
    }
  }

  if (std_lib_dir=="") {
    std::string mypath = FileUtils::progpath();
    if (!mypath.empty()) {
      if (FileUtils::file_exists(mypath+"/share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/share/minizinc";
      } else if (FileUtils::file_exists(mypath+"/../share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/../share/minizinc";
      } else if (FileUtils::file_exists(mypath+"/../../share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/../../share/minizinc";
      }
    }
  }

  if (std_lib_dir=="") {
    std::cerr << "Error: unknown minizinc standard library directory.\n"
    << "Specify --stdlib-dir on the command line or set the\n"
    << "MZN_STDLIB_DIR environment variable.\n";
    std::exit(EXIT_FAILURE);
  }

  includePaths.push_back(std_lib_dir+"/std/");

  {
    if (Model* outputm = parse(filename, std::vector<std::string>(), includePaths, false, false, false,
                               std::cerr)) {
      try {
        std::vector<TypeError> typeErrors;
        Env env(outputm);
        MiniZinc::typecheck(env,outputm,typeErrors);
        MiniZinc::registerBuiltins(env,outputm);

        typedef pair<VarDecl*,Expression*> DE;
        ASTStringMap<DE>::t declmap;
        Expression* outputExpr = NULL;
        for (unsigned int i=0; i<outputm->size(); i++) {
          if (VarDeclI* vdi = (*outputm)[i]->dyn_cast<VarDeclI>()) {
            declmap.insert(pair<ASTString,DE>(vdi->e()->id()->v(),DE(vdi->e(),vdi->e()->e())));
          } else if (OutputI* oi = (*outputm)[i]->dyn_cast<OutputI>()) {
            outputExpr = oi->e();
          }
        }

        //ostream& fout(flag_output_file.empty() ? std::cout : new fstream(flag_output_file));
        fstream file_ostream;
        if (!flag_output_file.empty())
            file_ostream.open(flag_output_file.c_str(), std::fstream::out);
        ostream& fout = flag_output_file.empty() ? std::cout : file_ostream;

        int solutions_found = 0;

        string solution;
        string comments;
        for (;;) {
          if (solstream.good()) {
            string line;
            getline(solstream, line);
            if (flag_ignore_lines > 0) {
              flag_ignore_lines--;
              continue;
            }
            if (line=="----------") {
              ++solutions_found;
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              // Put the "solution comma" before the solution itself,
              // but only for solutions after the first one.
              if (solutions_found > 1 && !solution_comma.empty())
                fout << solution_comma << std::endl;
              if (outputExpr != NULL) {
                for (unsigned int i=0; i<outputm->size(); i++) {
                  if (VarDeclI* vdi = (*outputm)[i]->dyn_cast<VarDeclI>()) {
                    ASTStringMap<DE>::t::iterator it = declmap.find(vdi->e()->id()->v());
                    vdi->e()->e(it->second.second);
                    vdi->e()->evaluated(false);
                  }
                }
                Model* sm = parseFromString(solution, "solution.szn", includePaths, true, false, false, cerr);
                for (unsigned int i=0; i<sm->size(); i++) {
                  if (AssignI* ai = (*sm)[i]->dyn_cast<AssignI>()) {
                    ASTStringMap<DE>::t::iterator it = declmap.find(ai->id());
                    if (it==declmap.end()) {
                      cerr << "Error: unexpected identifier " << ai->id() << " in output\n";
                      exit(EXIT_FAILURE);
                    }
                    ai->e()->type(it->second.first->type());
                    ai->decl(it->second.first);
                    typecheck(env,outputm, ai);
                    if (Call* c = ai->e()->dyn_cast<Call>()) {
                      // This is an arrayXd call, make sure we get the right builtin
                      assert(c->args()[c->args().size()-1]->isa<ArrayLit>());
                      for (unsigned int i=0; i<c->args().size(); i++)
                        c->args()[i]->type(Type::parsetint());
                      c->args()[c->args().size()-1]->type(it->second.first->type());
                      c->decl(outputm->matchFn(env.envi(),c));
                    }
                    it->second.first->e(ai->e());
                  }
                }
                delete sm;

                GCLock lock;
                ArrayLit* al = eval_array_lit(env.envi(),outputExpr);
                std::string os;
                for (unsigned int i=0; i<al->v().size(); i++) {
                  std::string s = eval_string(env.envi(),al->v()[i]);
                  if (!s.empty()) {
                    os = s;
                    fout << os;
                    if (flag_output_flush)
                      fout.flush();
                  }
                }
                if (!os.empty() && os[os.size()-1] != '\n')
                  fout << std::endl;
                  if (flag_output_flush)
                    fout.flush();
              }
              fout << comments;
              fout << solution_separator << std::endl;
              if (flag_output_flush)
                fout.flush();
              solution = "";
              comments = "";
            } else if (line=="==========") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << search_complete_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNSATISFIABLE=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unsatisfiable_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNBOUNDED=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unbounded_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNKNOWN=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unknown_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else {
              solution += line+"\n";
              size_t comment_pos = line.find('%');
              if (comment_pos != string::npos) {
                comments += line.substr(comment_pos);
                comments += "\n";
              }
            }
          } else {
            break;
          }
        }
        fout << comments;
        if (flag_output_flush)
          fout.flush();
      } catch (LocationException& e) {
        std::cerr << e.what() << ": " << e.msg() << std::endl;
        std::cerr << e.loc() << std::endl;
        exit(EXIT_FAILURE);
      } catch (Exception& e) {
        std::cerr << e.what() << ": " << e.msg() << std::endl;
        exit(EXIT_FAILURE);
      }
      delete outputm;
    }
  }

  return 0;

error:
  std::cerr << "Usage: "<< argv[0]
            << " [<options>] <model>.ozn" << std::endl
            << std::endl
            << "Options:" << std::endl
            << "  --help, -h\n    Print this help message." << std::endl
            << "  --version\n    Print version information." << std::endl
            << "  -o <file>, --output-to-file <file>\n    Filename for generated output." << std::endl
            << "  --stdlib-dir <dir>\n    Path to MiniZinc standard library directory." << std::endl
            << "  --no-output-comments\n    Do not print comments in the FlatZinc solution stream." << std::endl
            << "  --output-time\n    Print timing information in the FlatZinc solution stream." << std::endl
            << "  --no-flush-output\n    Don't flush output stream after every line." << std::endl
            << "  -i <n>, --ignore-lines <n>, --ignore-leading-lines <n>\n    Ignore the first <n> lines in the FlatZinc solution stream." << std::endl
            << "  --soln-sep <s>, --soln-separator <s>, --solution-separator <s>\n    Specify the string printed after each solution.\n    The default is to use the same as FlatZinc,\n    \"----------\"." << std::endl
            << "  --soln-comma <s>, --solution-comma <s>\n    Specify the string used to separate solutions.\n    The default is the empty string." << std::endl
            << "  --unsat-msg <msg>, --unsatisfiable-msg <msg>\n    Specify the message to print if the model instance is\n    unsatisfiable.\n    The default is to print \"=====UNSATISFIABLE=====\"." << std::endl
            << "  --unbounded-msg <msg>\n    Specify the message to print if the objective of the\n    model instance is unbounded.\n    The default is to print \"=====UNBOUNDED=====\"." << std::endl
            << "  --unknown-msg <msg>\n    Specify the message to print if search terminates without\n    the entire search space having been explored and no\n    solution has been found.\n    The default is to print \"=====UNKNOWN=====\"." << std::endl
            << "  --search-complete-msg <msg>\n    Specify the message to print if search terminates having\n    explored the entire search space.\n    The default is to print \"==========\"." << std::endl
  ;

  exit(EXIT_FAILURE);
}
<commit_msg>Handle errors in output produced by solver without crashing. Fixes #80.<commit_after>/* -*- mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*- */

/*
 *  Main authors:
 *     Guido Tack <guido.tack@monash.edu>
 */

/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifdef _MSC_VER
#define _CRT_SECURE_NO_WARNINGS
#endif

#include <iostream>
#include <fstream>
#include <iomanip>

#include <minizinc/model.hh>
#include <minizinc/parser.hh>
#include <minizinc/prettyprinter.hh>
#include <minizinc/typecheck.hh>
#include <minizinc/astexception.hh>
#include <minizinc/hash.hh>
#include <minizinc/eval_par.hh>
#include <minizinc/builtins.hh>
#include <minizinc/file_utils.hh>
#include <minizinc/timer.hh>

using namespace MiniZinc;
using namespace std;

std::string stoptime(Timer& timer) {
  std::ostringstream oss;
  oss << std::setprecision(0) << std::fixed << timer.ms() << " ms";
  return oss.str();
}

int main(int argc, char** argv) {
  Timer starttime;
  string filename;

  string flag_output_file;

  bool flag_output_comments = true;
  bool flag_output_flush = true;
  bool flag_output_time = false;
  string solfile;
  int flag_ignore_lines = 0;
  istream& solstream = cin;

  string solution_separator = "----------";
  string solution_comma     = "";
  string unsatisfiable_msg  = "=====UNSATISFIABLE=====";
  string unbounded_msg      = "=====UNBOUNDED=====";
  string unknown_msg        = "=====UNKNOWN=====";
  string search_complete_msg= "==========";

  vector<string> includePaths;
  string std_lib_dir;
  if (char* MZNSTDLIBDIR = getenv("MZN_STDLIB_DIR")) {
    std_lib_dir = string(MZNSTDLIBDIR);
  }

  if (argc < 2)
    goto error;

  for (int i=1; i<argc; i++) {
    if (string(argv[i])==string("--version")) {
      std::cout << "NICTA MiniZinc solution printing tool, version "
      << MZN_VERSION_MAJOR << "." << MZN_VERSION_MINOR << "." << MZN_VERSION_PATCH << std::endl;
      std::cout << "Copyright (C) 2014, 2015 Monash University and NICTA" << std::endl;
      std::exit(EXIT_SUCCESS);
    }
    if (string(argv[i])==string("-h") || string(argv[i])==string("--help")) {
        goto error;
    } else if (string(argv[i])=="-o" || string(argv[i])=="--output-to-file") {
      i++;
      if (i==argc)
        goto error;
      flag_output_file = argv[i];
    } else if (string(argv[i])=="--stdlib-dir") {
      i++;
      if (i==argc)
        goto error;
      std_lib_dir = argv[i];
    } else if (string(argv[i])=="--no-flush-output") {
      flag_output_flush = false;
    } else if (string(argv[i])=="--no-output-comments") {
      flag_output_comments = false;
    } else if (string(argv[i])=="-i" ||
               string(argv[i])=="--ignore-lines" ||
               string(argv[i])=="--ignore-leading-lines") {
      ++i;
      if (i==argc)
        goto error;
      flag_ignore_lines = atoi(argv[i]);
    } else if (string(argv[i])=="--soln-sep" ||
               string(argv[i])=="--soln-separator" ||
               string(argv[i])=="--solution-separator") {
      ++i;
      if (i==argc)
        goto error;
      solution_separator = string(argv[i]);
    } else if (string(argv[i])=="--soln-comma" ||
               string(argv[i])=="--solution-comma") {
      ++i;
      if (i==argc)
        goto error;
      solution_comma = string(argv[i]);
    } else if (string(argv[i])=="--unsat-msg" ||
               string(argv[i])=="--unsatisfiable-msg") {
      ++i;
      if (i==argc)
        goto error;
      unsatisfiable_msg = string(argv[i]);
    } else if (string(argv[i])=="--unbounded-msg") {
      ++i;
      if (i==argc)
        goto error;
      unbounded_msg = string(argv[i]);
    } else if (string(argv[i])=="--unknown-msg") {
      ++i;
      if (i==argc)
        goto error;
      unknown_msg = string(argv[i]);
    } else if (string(argv[i])=="--search-complete-msg") {
      ++i;
      if (i==argc)
        goto error;
      search_complete_msg = string(argv[i]);
    } else if (string(argv[i])=="--output-time") {
      flag_output_time = true;
    } else {
      filename = argv[i++];
      if (filename.length()<=4 ||
          filename.substr(filename.length()-4,string::npos) != ".ozn") {
        std::cerr << "Invalid .ozn file " << filename << "." << std::endl;
        goto error;
      }
    }
  }

  if (std_lib_dir=="") {
    std::string mypath = FileUtils::progpath();
    if (!mypath.empty()) {
      if (FileUtils::file_exists(mypath+"/share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/share/minizinc";
      } else if (FileUtils::file_exists(mypath+"/../share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/../share/minizinc";
      } else if (FileUtils::file_exists(mypath+"/../../share/minizinc/std/builtins.mzn")) {
        std_lib_dir = mypath+"/../../share/minizinc";
      }
    }
  }

  if (std_lib_dir=="") {
    std::cerr << "Error: unknown minizinc standard library directory.\n"
    << "Specify --stdlib-dir on the command line or set the\n"
    << "MZN_STDLIB_DIR environment variable.\n";
    std::exit(EXIT_FAILURE);
  }

  includePaths.push_back(std_lib_dir+"/std/");

  {
    if (Model* outputm = parse(filename, std::vector<std::string>(), includePaths, false, false, false,
                               std::cerr)) {
      try {
        std::vector<TypeError> typeErrors;
        Env env(outputm);
        MiniZinc::typecheck(env,outputm,typeErrors);
        MiniZinc::registerBuiltins(env,outputm);

        typedef pair<VarDecl*,Expression*> DE;
        ASTStringMap<DE>::t declmap;
        Expression* outputExpr = NULL;
        for (unsigned int i=0; i<outputm->size(); i++) {
          if (VarDeclI* vdi = (*outputm)[i]->dyn_cast<VarDeclI>()) {
            declmap.insert(pair<ASTString,DE>(vdi->e()->id()->v(),DE(vdi->e(),vdi->e()->e())));
          } else if (OutputI* oi = (*outputm)[i]->dyn_cast<OutputI>()) {
            outputExpr = oi->e();
          }
        }

        //ostream& fout(flag_output_file.empty() ? std::cout : new fstream(flag_output_file));
        fstream file_ostream;
        if (!flag_output_file.empty())
            file_ostream.open(flag_output_file.c_str(), std::fstream::out);
        ostream& fout = flag_output_file.empty() ? std::cout : file_ostream;

        int solutions_found = 0;

        string solution;
        string comments;
        for (;;) {
          if (solstream.good()) {
            string line;
            getline(solstream, line);
            if (flag_ignore_lines > 0) {
              flag_ignore_lines--;
              continue;
            }
            if (line=="----------") {
              ++solutions_found;
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              // Put the "solution comma" before the solution itself,
              // but only for solutions after the first one.
              if (solutions_found > 1 && !solution_comma.empty())
                fout << solution_comma << std::endl;
              if (outputExpr != NULL) {
                for (unsigned int i=0; i<outputm->size(); i++) {
                  if (VarDeclI* vdi = (*outputm)[i]->dyn_cast<VarDeclI>()) {
                    ASTStringMap<DE>::t::iterator it = declmap.find(vdi->e()->id()->v());
                    vdi->e()->e(it->second.second);
                    vdi->e()->evaluated(false);
                  }
                }
                Model* sm = parseFromString(solution, "solution received from solver", includePaths, true, false, false, cerr);
                if (!sm) {
                  exit(EXIT_FAILURE);
                }
                for (unsigned int i=0; i<sm->size(); i++) {
                  if (AssignI* ai = (*sm)[i]->dyn_cast<AssignI>()) {
                    ASTStringMap<DE>::t::iterator it = declmap.find(ai->id());
                    if (it==declmap.end()) {
                      cerr << "Error: unexpected identifier " << ai->id() << " in output\n";
                      exit(EXIT_FAILURE);
                    }
                    ai->e()->type(it->second.first->type());
                    ai->decl(it->second.first);
                    typecheck(env,outputm, ai);
                    if (Call* c = ai->e()->dyn_cast<Call>()) {
                      // This is an arrayXd call, make sure we get the right builtin
                      assert(c->args()[c->args().size()-1]->isa<ArrayLit>());
                      for (unsigned int i=0; i<c->args().size(); i++)
                        c->args()[i]->type(Type::parsetint());
                      c->args()[c->args().size()-1]->type(it->second.first->type());
                      c->decl(outputm->matchFn(env.envi(),c));
                    }
                    it->second.first->e(ai->e());
                  }
                }
                delete sm;

                GCLock lock;
                ArrayLit* al = eval_array_lit(env.envi(),outputExpr);
                std::string os;
                for (unsigned int i=0; i<al->v().size(); i++) {
                  std::string s = eval_string(env.envi(),al->v()[i]);
                  if (!s.empty()) {
                    os = s;
                    fout << os;
                    if (flag_output_flush)
                      fout.flush();
                  }
                }
                if (!os.empty() && os[os.size()-1] != '\n')
                  fout << std::endl;
                  if (flag_output_flush)
                    fout.flush();
              }
              fout << comments;
              fout << solution_separator << std::endl;
              if (flag_output_flush)
                fout.flush();
              solution = "";
              comments = "";
            } else if (line=="==========") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << search_complete_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNSATISFIABLE=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unsatisfiable_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNBOUNDED=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unbounded_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else if(line=="=====UNKNOWN=====") {
              if (flag_output_time)
                fout << "% time elapsed: " << stoptime(starttime) << "\n";
              fout << unknown_msg << std::endl;
              if (flag_output_flush)
                fout.flush();
            } else {
              solution += line+"\n";
              size_t comment_pos = line.find('%');
              if (comment_pos != string::npos) {
                comments += line.substr(comment_pos);
                comments += "\n";
              }
            }
          } else {
            break;
          }
        }
        fout << comments;
        if (flag_output_flush)
          fout.flush();
      } catch (LocationException& e) {
        std::cerr << e.what() << ": " << e.msg() << std::endl;
        std::cerr << e.loc() << std::endl;
        exit(EXIT_FAILURE);
      } catch (Exception& e) {
        std::cerr << e.what() << ": " << e.msg() << std::endl;
        exit(EXIT_FAILURE);
      }
      delete outputm;
    }
  }

  return 0;

error:
  std::cerr << "Usage: "<< argv[0]
            << " [<options>] <model>.ozn" << std::endl
            << std::endl
            << "Options:" << std::endl
            << "  --help, -h\n    Print this help message." << std::endl
            << "  --version\n    Print version information." << std::endl
            << "  -o <file>, --output-to-file <file>\n    Filename for generated output." << std::endl
            << "  --stdlib-dir <dir>\n    Path to MiniZinc standard library directory." << std::endl
            << "  --no-output-comments\n    Do not print comments in the FlatZinc solution stream." << std::endl
            << "  --output-time\n    Print timing information in the FlatZinc solution stream." << std::endl
            << "  --no-flush-output\n    Don't flush output stream after every line." << std::endl
            << "  -i <n>, --ignore-lines <n>, --ignore-leading-lines <n>\n    Ignore the first <n> lines in the FlatZinc solution stream." << std::endl
            << "  --soln-sep <s>, --soln-separator <s>, --solution-separator <s>\n    Specify the string printed after each solution.\n    The default is to use the same as FlatZinc,\n    \"----------\"." << std::endl
            << "  --soln-comma <s>, --solution-comma <s>\n    Specify the string used to separate solutions.\n    The default is the empty string." << std::endl
            << "  --unsat-msg <msg>, --unsatisfiable-msg <msg>\n    Specify the message to print if the model instance is\n    unsatisfiable.\n    The default is to print \"=====UNSATISFIABLE=====\"." << std::endl
            << "  --unbounded-msg <msg>\n    Specify the message to print if the objective of the\n    model instance is unbounded.\n    The default is to print \"=====UNBOUNDED=====\"." << std::endl
            << "  --unknown-msg <msg>\n    Specify the message to print if search terminates without\n    the entire search space having been explored and no\n    solution has been found.\n    The default is to print \"=====UNKNOWN=====\"." << std::endl
            << "  --search-complete-msg <msg>\n    Specify the message to print if search terminates having\n    explored the entire search space.\n    The default is to print \"==========\"." << std::endl
  ;

  exit(EXIT_FAILURE);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "log.h"

#include "datetime.h"
#include "utils.h"

#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>

#define BUFFER_SIZE (10 * 1024)

const std::regex filter_re("\033\\[[;\\d]*m");

const char *priorities[] = {
	EMERG_COL "█" NO_COL,   // LOG_EMERG    0 = System is unusable
	ALERT_COL "▉" NO_COL,   // LOG_ALERT    1 = Action must be taken immediately
	CRIT_COL "▊" NO_COL,    // LOG_CRIT     2 = Critical conditions
	ERR_COL "▋" NO_COL,     // LOG_ERR      3 = Error conditions
	WARNING_COL "▌" NO_COL, // LOG_WARNING  4 = Warning conditions
	NOTICE_COL "▍" NO_COL,  // LOG_NOTICE   5 = Normal but significant condition
	INFO_COL "▎" NO_COL,    // LOG_INFO     6 = Informational
	DEBUG_COL "▏" NO_COL,   // LOG_DEBUG    7 = Debug-level messages
};

void
StreamLogger::log(int priority, const std::string& str)
{
	ofs << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
}

void
StderrLogger::log(int priority, const std::string& str)
{
	if (isatty(fileno(stderr))) {
		std::cerr << priorities[priority < 0 ? -priority : priority] + str << std::endl;
	} else {
		std::cerr << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
	}
}

SysLog::SysLog(const char *ident, int option, int facility)
{
	openlog(ident, option, facility);
}

SysLog::~SysLog()
{
	closelog();
}

void
SysLog::log(int priority, const std::string& str)
{
	syslog(priority, "%s", std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "").c_str());
}

int Log::log_level = DEFAULT_LOG_LEVEL;
std::vector<std::unique_ptr<Logger>> Log::handlers;

Log::Log(const std::string& str, bool cleanup_, std::chrono::time_point<std::chrono::system_clock> wakeup_, int priority_)
	: cleanup(cleanup_),
	  wakeup(wakeup_),
	  str_start(str),
	  priority(priority_),
	  finished(false) { }

Log::~Log()
{
	bool f = false;
	finished.compare_exchange_strong(f, cleanup);
}

/*
 * https://isocpp.org/wiki/faq/ctors#static-init-order
 * Avoid the "static initialization order fiasco"
 */
LogThread&
Log::_thread()
{
	static LogThread* thread_ = new LogThread();
	return *thread_;
}

std::string
Log::str_format(int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void* obj, const char *format, va_list argptr)
{
	char* buffer = new char[BUFFER_SIZE];
	vsnprintf(buffer, BUFFER_SIZE, format, argptr);
	std::string msg(buffer);
	auto iso8601 = "[" + Datetime::to_string(std::chrono::system_clock::now()) + "]";
	auto tid = " (" + get_thread_name() + ")";
	std::string result = iso8601 + tid;
#ifdef TRACEBACK
	if (obj) {
		snprintf(buffer, BUFFER_SIZE, " [%p]", obj);
		result += buffer;
	}
	auto location = (priority >= LOCATION_LOG_LEVEL) ? " " + std::string(file) + ":" + std::to_string(line) : std::string();
	result += location + ": ";
#endif
	result += prefix + msg + suffix;
	delete []buffer;
	if (priority < 0) {
		if (exc.empty()) {
			result += DARK_GREY + traceback(file, line) + NO_COL;
		} else {
			result += NO_COL + exc + NO_COL;
		}
	}
	return result;
}

std::shared_ptr<Log>
Log::log(bool cleanup, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	va_list argptr;
	va_start(argptr, format);
	std::string str(str_format(priority, exc, file, line, suffix, prefix, obj, format, argptr));
	va_end(argptr);

	return print(str, cleanup, wakeup, priority);
}

void
Log::clear()
{
	finished.store(true);
}

void
Log::unlog(int priority, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	if (finished.exchange(true)) {
		va_list argptr;
		va_start(argptr, format);
		std::string str(str_format(priority, nullptr, file, line, suffix, prefix, obj, format, argptr));
		va_end(argptr);

		print(str, false, 0, priority);
	}
}

std::shared_ptr<Log>
Log::add(const std::string& str, bool cleanup, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority)
{
	auto l_ptr = std::make_shared<Log>(str, cleanup, wakeup, priority);

	static LogThread& thread = _thread();
	thread.add(l_ptr);

	return l_ptr;
}

void
Log::log(int priority, const std::string& str)
{
	static std::mutex log_mutex;
	std::lock_guard<std::mutex> lk(log_mutex);
	for (auto& handler : Log::handlers) {
		handler->log(priority, str);
	}
}

std::shared_ptr<Log>
Log::print(const std::string& str, bool cleanup, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority)
{
	if (priority > Log::log_level) {
		return std::make_shared<Log>(str, cleanup, wakeup, priority);
	}

	if (!Log::handlers.size()) {
		Log::handlers.push_back(std::make_unique<StderrLogger>());
	}

	if (priority >= ASYNC_LOG_LEVEL || wakeup > std::chrono::system_clock::now()) {
		return add(str, cleanup, wakeup, priority);
	} else {
		log(priority, str);
		return std::make_shared<Log>(str, cleanup, wakeup, priority);
	}
}

void
Log::finish(bool wait)
{
	static LogThread& thread = _thread();
	thread.finish(wait);
}

LogThread::LogThread()
	: running(true),
	  inner_thread(&LogThread::thread_function, this) { }

LogThread::~LogThread()
{
	finish(true);
}

void
LogThread::finish(bool wait)
{
	running.store(false);
	wakeup_signal.notify_all();
	if (wait) {
		try {
			inner_thread.join();
		} catch (const std::system_error&) { }
	}
}

void
LogThread::add(const std::shared_ptr<Log>& l_ptr)
{
	if (running.load()) {
		log_list.push_back(l_ptr->shared_from_this());

		if (std::chrono::system_clock::from_time_t(wakeup.load()) >= l_ptr->wakeup) {
			wakeup_signal.notify_all();
		}
	}
}

void
LogThread::thread_function()
{
	std::mutex mtx;
	std::unique_lock<std::mutex> lk(mtx);

	auto now = std::chrono::system_clock::now();
	auto next_wakeup = now + 3s;

	while (running.load()) {
		wakeup.store(std::chrono::system_clock::to_time_t(next_wakeup));
		wakeup_signal.wait_until(lk, next_wakeup);

		now = std::chrono::system_clock::now();
		next_wakeup = now + 3s;

		for (auto it = log_list.begin(); it != log_list.end(); ) {
			auto& l_ptr = *it;
			if (!l_ptr || l_ptr->finished.load()) {
				it = log_list.erase(it);
			} else if (l_ptr->wakeup <= now) {
				l_ptr->finished.store(true);
				Log::log(l_ptr->priority, l_ptr->str_start);
				it = log_list.erase(it);
			} else if (next_wakeup > l_ptr->wakeup) {
				next_wakeup = l_ptr->wakeup;
				++it;
			} else {
				++it;
			}
		}
		if (next_wakeup < now + 100ms) {
			next_wakeup = now + 100ms;
		}
	}
}
<commit_msg>Format<commit_after>/*
 * Copyright (C) 2015 deipi.com LLC and contributors. All rights reserved.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

#include "log.h"

#include "datetime.h"
#include "utils.h"

#include <stdarg.h>
#include <unistd.h>
#include <stdio.h>

#define BUFFER_SIZE (10 * 1024)

const std::regex filter_re("\033\\[[;\\d]*m");

const char *priorities[] = {
	EMERG_COL "█" NO_COL,   // LOG_EMERG    0 = System is unusable
	ALERT_COL "▉" NO_COL,   // LOG_ALERT    1 = Action must be taken immediately
	CRIT_COL "▊" NO_COL,    // LOG_CRIT     2 = Critical conditions
	ERR_COL "▋" NO_COL,     // LOG_ERR      3 = Error conditions
	WARNING_COL "▌" NO_COL, // LOG_WARNING  4 = Warning conditions
	NOTICE_COL "▍" NO_COL,  // LOG_NOTICE   5 = Normal but significant condition
	INFO_COL "▎" NO_COL,    // LOG_INFO     6 = Informational
	DEBUG_COL "▏" NO_COL,   // LOG_DEBUG    7 = Debug-level messages
};

void
StreamLogger::log(int priority, const std::string& str)
{
	ofs << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
}

void
StderrLogger::log(int priority, const std::string& str)
{
	if (isatty(fileno(stderr))) {
		std::cerr << priorities[priority < 0 ? -priority : priority] + str << std::endl;
	} else {
		std::cerr << std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "") << std::endl;
	}
}

SysLog::SysLog(const char *ident, int option, int facility)
{
	openlog(ident, option, facility);
}

SysLog::~SysLog()
{
	closelog();
}

void
SysLog::log(int priority, const std::string& str)
{
	syslog(priority, "%s", std::regex_replace(priorities[priority < 0 ? -priority : priority] + str, filter_re, "").c_str());
}

int Log::log_level = DEFAULT_LOG_LEVEL;
std::vector<std::unique_ptr<Logger>> Log::handlers;

Log::Log(const std::string& str, bool cleanup_, std::chrono::time_point<std::chrono::system_clock> wakeup_, int priority_)
	: cleanup(cleanup_),
	  wakeup(wakeup_),
	  str_start(str),
	  priority(priority_),
	  finished(false) { }

Log::~Log()
{
	bool f = false;
	finished.compare_exchange_strong(f, cleanup);
}

/*
 * https://isocpp.org/wiki/faq/ctors#static-init-order
 * Avoid the "static initialization order fiasco"
 */
LogThread&
Log::_thread()
{
	static LogThread* thread = new LogThread();
	return *thread;
}

std::string
Log::str_format(int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void* obj, const char *format, va_list argptr)
{
	char* buffer = new char[BUFFER_SIZE];
	vsnprintf(buffer, BUFFER_SIZE, format, argptr);
	std::string msg(buffer);
	auto iso8601 = "[" + Datetime::to_string(std::chrono::system_clock::now()) + "]";
	auto tid = " (" + get_thread_name() + ")";
	std::string result = iso8601 + tid;
#ifdef TRACEBACK
	if (obj) {
		snprintf(buffer, BUFFER_SIZE, " [%p]", obj);
		result += buffer;
	}
	auto location = (priority >= LOCATION_LOG_LEVEL) ? " " + std::string(file) + ":" + std::to_string(line) : std::string();
	result += location + ": ";
#endif
	result += prefix + msg + suffix;
	delete []buffer;
	if (priority < 0) {
		if (exc.empty()) {
			result += DARK_GREY + traceback(file, line) + NO_COL;
		} else {
			result += NO_COL + exc + NO_COL;
		}
	}
	return result;
}

std::shared_ptr<Log>
Log::log(bool cleanup, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority, const std::string& exc, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	va_list argptr;
	va_start(argptr, format);
	std::string str(str_format(priority, exc, file, line, suffix, prefix, obj, format, argptr));
	va_end(argptr);

	return print(str, cleanup, wakeup, priority);
}

void
Log::clear()
{
	finished.store(true);
}

void
Log::unlog(int priority, const char *file, int line, const char *suffix, const char *prefix, const void *obj, const char *format, ...)
{
	if (finished.exchange(true)) {
		va_list argptr;
		va_start(argptr, format);
		std::string str(str_format(priority, nullptr, file, line, suffix, prefix, obj, format, argptr));
		va_end(argptr);

		print(str, false, 0, priority);
	}
}

std::shared_ptr<Log>
Log::add(const std::string& str, bool cleanup, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority)
{
	auto l_ptr = std::make_shared<Log>(str, cleanup, wakeup, priority);

	static LogThread& thread = _thread();
	thread.add(l_ptr);

	return l_ptr;
}

void
Log::log(int priority, const std::string& str)
{
	static std::mutex log_mutex;
	std::lock_guard<std::mutex> lk(log_mutex);
	for (auto& handler : Log::handlers) {
		handler->log(priority, str);
	}
}

std::shared_ptr<Log>
Log::print(const std::string& str, bool cleanup, std::chrono::time_point<std::chrono::system_clock> wakeup, int priority)
{
	if (priority > Log::log_level) {
		return std::make_shared<Log>(str, cleanup, wakeup, priority);
	}

	if (!Log::handlers.size()) {
		Log::handlers.push_back(std::make_unique<StderrLogger>());
	}

	if (priority >= ASYNC_LOG_LEVEL || wakeup > std::chrono::system_clock::now()) {
		return add(str, cleanup, wakeup, priority);
	} else {
		log(priority, str);
		return std::make_shared<Log>(str, cleanup, wakeup, priority);
	}
}

void
Log::finish(bool wait)
{
	static LogThread& thread = _thread();
	thread.finish(wait);
}

LogThread::LogThread()
	: running(true),
	  inner_thread(&LogThread::thread_function, this) { }

LogThread::~LogThread()
{
	finish(true);
}

void
LogThread::finish(bool wait)
{
	running.store(false);
	wakeup_signal.notify_all();
	if (wait) {
		try {
			inner_thread.join();
		} catch (const std::system_error&) { }
	}
}

void
LogThread::add(const std::shared_ptr<Log>& l_ptr)
{
	if (running.load()) {
		log_list.push_back(l_ptr->shared_from_this());

		if (std::chrono::system_clock::from_time_t(wakeup.load()) >= l_ptr->wakeup) {
			wakeup_signal.notify_all();
		}
	}
}

void
LogThread::thread_function()
{
	std::mutex mtx;
	std::unique_lock<std::mutex> lk(mtx);

	auto now = std::chrono::system_clock::now();
	auto next_wakeup = now + 3s;

	while (running.load()) {
		wakeup.store(std::chrono::system_clock::to_time_t(next_wakeup));
		wakeup_signal.wait_until(lk, next_wakeup);

		now = std::chrono::system_clock::now();
		next_wakeup = now + 3s;

		for (auto it = log_list.begin(); it != log_list.end(); ) {
			auto& l_ptr = *it;
			if (!l_ptr || l_ptr->finished.load()) {
				it = log_list.erase(it);
			} else if (l_ptr->wakeup <= now) {
				l_ptr->finished.store(true);
				Log::log(l_ptr->priority, l_ptr->str_start);
				it = log_list.erase(it);
			} else if (next_wakeup > l_ptr->wakeup) {
				next_wakeup = l_ptr->wakeup;
				++it;
			} else {
				++it;
			}
		}
		if (next_wakeup < now + 100ms) {
			next_wakeup = now + 100ms;
		}
	}
}
<|endoftext|>