<commit_before>// ======================================================================== //
// Copyright 2009-2013 Intel Corporation                                    //
//                                                                          //
// 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 "glutdisplay.h"
#include "sys/filename.h"
#include "lexers/streamfilters.h"
#include "lexers/parsestream.h"
#include "transport/transport_host.h"

/* include GLUT for display */
#if defined(__MACOSX__)
#  include <OpenGL/gl.h>
#  include <GLUT/glut.h>
#  include <ApplicationServices/ApplicationServices.h>
#elif defined(__WIN32__)
#  include <windows.h>
#  include <GL/gl.h>
#  include <GL/glut.h>
#else
#  include <GL/gl.h>
#  include <GL/glut.h>
#endif

namespace embree
{
  static const double g_time0 = getSeconds();

  /* camera */
  Camera g_camera;

  /* output settings */
  static size_t g_width = 512;
  static size_t g_height = 512;

  /* fullscreen settings */
  static bool g_fullscreen = false;
  static size_t g_window_width = 512;
  static size_t g_window_height = 512;

  /* ID of created window */
  static int g_window = 0;

  /*************************************************************************************************/
  /*                                  Keyboard control                                             */
  /*************************************************************************************************/

  static float g_speed = 1.0f;

  void keyboardFunc(unsigned char k, int, int)
  {
    key_pressed(k);

    switch (k)
    {
    case 'f' :
      if (g_fullscreen) {
        g_fullscreen = false;
        glutReshapeWindow(g_window_width,g_window_height);
      } else {
        g_fullscreen = true;
        g_window_width = g_width;
        g_window_height = g_height;
        glutFullScreen();
      }
      break;
    case 'c' : {
      std::cout << "-vp " << g_camera.from.x    << " " << g_camera.from.y    << " " << g_camera.from.z    << " " << std::endl
                << "-vi " << g_camera.to.x << " " << g_camera.to.y << " " << g_camera.to.z << " " << std::endl
                << "-vu " << g_camera.up.x     << " " << g_camera.up.y     << " " << g_camera.up.z     << " " << std::endl
                << "-fov " << g_camera.fov << std::endl;
      break;
    }
    case 'a' : g_camera.rotate(-0.02f,0.0f); break;
    case 'd' : g_camera.rotate(+0.02f,0.0f); break;
    case 'w' : g_camera.move(0.0f,0.0f,+g_speed); break;
    case 's' : g_camera.move(0.0f,0.0f,-g_speed); break;
    case '\033': case 'q': case 'Q':
      cleanup();
      glutDestroyWindow(g_window);
      exit(0);
      break;
    }
  }

  void specialFunc(int k, int, int)
  {
    key_pressed(k);

    switch (k) {
    case GLUT_KEY_LEFT      : g_camera.rotate(-0.02f,0.0f); break;
    case GLUT_KEY_RIGHT     : g_camera.rotate(+0.02f,0.0f); break;
    case GLUT_KEY_UP        : g_camera.move(0.0f,0.0f,+g_speed); break;
    case GLUT_KEY_DOWN      : g_camera.move(0.0f,0.0f,-g_speed); break;
    case GLUT_KEY_PAGE_UP   : g_speed *= 1.2f; break;
    case GLUT_KEY_PAGE_DOWN : g_speed /= 1.2f; break;
    }
  }

  /*************************************************************************************************/
  /*                                   Mouse control                                               */
  /*************************************************************************************************/

  static int mouseMode = 0;
  static int clickX = 0, clickY = 0;
  static bool flip14 = false;

  void clickFunc(int button, int state, int x, int y)
  {
    if (state == GLUT_UP)
    {
      mouseMode = 0;
      if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == GLUT_ACTIVE_CTRL)
      {
        AffineSpace3f pixel2world = g_camera.pixel2world(g_width,g_height);
        Vec3f p; bool hit = pick(x,y, pixel2world.l.vx, pixel2world.l.vy, pixel2world.l.vz, pixel2world.p, p);

        if (hit) {
          Vec3fa delta = p - g_camera.to;
          Vec3fa right = normalize(pixel2world.l.vx);
          Vec3fa up    = normalize(pixel2world.l.vy);
          g_camera.to = p;
          g_camera.from += dot(delta,right)*right + dot(delta,up)*up;
        }
      }
      else if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_SHIFT))
      {
        AffineSpace3f pixel2world = g_camera.pixel2world(g_width,g_height);
        Vec3f p; bool hit = pick(x,y, pixel2world.l.vx, pixel2world.l.vy, pixel2world.l.vz, pixel2world.p, p);
        if (hit) g_camera.to = p;
      }

    } else {
      clickX = x; clickY = y;
      int modifiers = glutGetModifiers();
      if      (button == GLUT_LEFT_BUTTON && modifiers == GLUT_ACTIVE_SHIFT) mouseMode = 1;
      else if (button == GLUT_MIDDLE_BUTTON) mouseMode = 2;
      else if (button == GLUT_RIGHT_BUTTON ) mouseMode = 3;
      else if (button == GLUT_LEFT_BUTTON  ) mouseMode = 4;

      if (flip14) {
        if (mouseMode == 4) mouseMode = 1;
        else if (mouseMode == 1) mouseMode = 4;
      }
    }
  }

  void motionFunc(int x, int y)
  {
    float dClickX = float(clickX - x), dClickY = float(clickY - y);
    clickX = x; clickY = y;

    switch (mouseMode) {
    case 1: g_camera.rotateOrbit(-0.005f*dClickX,0.005f*dClickY); break;
    case 2: break;
    case 3: g_camera.dolly(-dClickY); break;
    case 4: g_camera.rotate(-0.005f*dClickX,0.005f*dClickY); break;
    }
  }

  /*************************************************************************************************/
  /*                                   Window control                                              */
  /*************************************************************************************************/

  void displayFunc(void)
  {
    AffineSpace3f pixel2world = g_camera.pixel2world(g_width,g_height);

    /* render image using ISPC */
    double t0 = getSeconds();
    render(g_time0-t0,
           pixel2world.l.vx,
           pixel2world.l.vy,
           pixel2world.l.vz,
           pixel2world.p);
    double dt0 = getSeconds()-t0;

    /* draw pixels to screen */
    int* pixels = map();
    glRasterPos2i(-1, 1);
    glPixelZoom(1.0f, -1.0f);
    glDrawPixels(g_width,g_height,GL_RGBA,GL_UNSIGNED_BYTE,pixels);
    glutSwapBuffers();
    unmap();
    double dt1 = getSeconds()-t0;

    /* print frame rate */
    std::ostringstream stream;
    stream.setf(std::ios::fixed, std::ios::floatfield);
    stream.precision(2);
    stream << "render: ";
    stream << 1.0f/dt0 << " fps, ";
    stream << dt0*1000.0f << " ms, ";
    stream << "display: ";
    stream << 1.0f/dt1 << " fps, ";
    stream << dt1*1000.0f << " ms, ";
    stream << g_width << "x" << g_height << " pixels";
    std::cout << stream.str() << std::endl;
  }

  void reshapeFunc(int width, int height)
  {
    resize(width,height);
    glViewport(0, 0, width, height);
    g_width = width; g_height = height;
  }

  void idleFunc() {
    glutPostRedisplay();
  }

  /* initialize GLUT */
  void initGlut (const std::string name, const size_t width, const size_t height, const bool fullscreen, const bool mouseMode)
  {
    g_width = width;
    g_height = height;
    resize(g_width,g_height);

    g_fullscreen = fullscreen;
    flip14 = mouseMode;
    int argc = 0; char** argv = NULL;
    glutInit(&argc, argv);
    glutInitWindowSize((GLsizei)g_width, (GLsizei)g_height);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowPosition(0, 0);
    g_window = glutCreateWindow(name.c_str());
    if (g_fullscreen) glutFullScreen();
    glutDisplayFunc(displayFunc);
    glutIdleFunc(idleFunc);
    glutKeyboardFunc(keyboardFunc);
    glutSpecialFunc(specialFunc);
    glutMouseFunc(clickFunc);
    glutMotionFunc(motionFunc);
    glutReshapeFunc(reshapeFunc);
    glutMainLoop();
  }
}
<commit_msg>space disables display in tutorials<commit_after>// ======================================================================== //
// Copyright 2009-2013 Intel Corporation                                    //
//                                                                          //
// 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 "glutdisplay.h"
#include "sys/filename.h"
#include "lexers/streamfilters.h"
#include "lexers/parsestream.h"
#include "transport/transport_host.h"

/* include GLUT for display */
#if defined(__MACOSX__)
#  include <OpenGL/gl.h>
#  include <GLUT/glut.h>
#  include <ApplicationServices/ApplicationServices.h>
#elif defined(__WIN32__)
#  include <windows.h>
#  include <GL/gl.h>
#  include <GL/glut.h>
#else
#  include <GL/gl.h>
#  include <GL/glut.h>
#endif

namespace embree
{
  static const double g_time0 = getSeconds();

  /* camera */
  Camera g_camera;

  /* output settings */
  static size_t g_width = 512;
  static size_t g_height = 512;
  static bool g_display = true;

  /* fullscreen settings */
  static bool g_fullscreen = false;
  static size_t g_window_width = 512;
  static size_t g_window_height = 512;

  /* ID of created window */
  static int g_window = 0;

  /*************************************************************************************************/
  /*                                  Keyboard control                                             */
  /*************************************************************************************************/

  static float g_speed = 1.0f;

  void keyboardFunc(unsigned char k, int, int)
  {
    key_pressed(k);

    switch (k)
    {
    case 'f' :
      if (g_fullscreen) {
        g_fullscreen = false;
        glutReshapeWindow(g_window_width,g_window_height);
      } else {
        g_fullscreen = true;
        g_window_width = g_width;
        g_window_height = g_height;
        glutFullScreen();
      }
      break;
    case 'c' : {
      std::cout << "-vp " << g_camera.from.x    << " " << g_camera.from.y    << " " << g_camera.from.z    << " " << std::endl
                << "-vi " << g_camera.to.x << " " << g_camera.to.y << " " << g_camera.to.z << " " << std::endl
                << "-vu " << g_camera.up.x     << " " << g_camera.up.y     << " " << g_camera.up.z     << " " << std::endl
                << "-fov " << g_camera.fov << std::endl;
      break;
    }
    case 'a' : g_camera.rotate(-0.02f,0.0f); break;
    case 'd' : g_camera.rotate(+0.02f,0.0f); break;
    case 'w' : g_camera.move(0.0f,0.0f,+g_speed); break;
    case 's' : g_camera.move(0.0f,0.0f,-g_speed); break;
    case ' ' : g_display = !g_display; break;
    case '\033': case 'q': case 'Q':
      cleanup();
      glutDestroyWindow(g_window);
      exit(0);
      break;
    }
  }

  void specialFunc(int k, int, int)
  {
    key_pressed(k);

    switch (k) {
    case GLUT_KEY_LEFT      : g_camera.rotate(-0.02f,0.0f); break;
    case GLUT_KEY_RIGHT     : g_camera.rotate(+0.02f,0.0f); break;
    case GLUT_KEY_UP        : g_camera.move(0.0f,0.0f,+g_speed); break;
    case GLUT_KEY_DOWN      : g_camera.move(0.0f,0.0f,-g_speed); break;
    case GLUT_KEY_PAGE_UP   : g_speed *= 1.2f; break;
    case GLUT_KEY_PAGE_DOWN : g_speed /= 1.2f; break;
    }
  }

  /*************************************************************************************************/
  /*                                   Mouse control                                               */
  /*************************************************************************************************/

  static int mouseMode = 0;
  static int clickX = 0, clickY = 0;
  static bool flip14 = false;

  void clickFunc(int button, int state, int x, int y)
  {
    if (state == GLUT_UP)
    {
      mouseMode = 0;
      if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == GLUT_ACTIVE_CTRL)
      {
        AffineSpace3f pixel2world = g_camera.pixel2world(g_width,g_height);
        Vec3f p; bool hit = pick(x,y, pixel2world.l.vx, pixel2world.l.vy, pixel2world.l.vz, pixel2world.p, p);

        if (hit) {
          Vec3fa delta = p - g_camera.to;
          Vec3fa right = normalize(pixel2world.l.vx);
          Vec3fa up    = normalize(pixel2world.l.vy);
          g_camera.to = p;
          g_camera.from += dot(delta,right)*right + dot(delta,up)*up;
        }
      }
      else if (button == GLUT_LEFT_BUTTON && glutGetModifiers() == (GLUT_ACTIVE_CTRL | GLUT_ACTIVE_SHIFT))
      {
        AffineSpace3f pixel2world = g_camera.pixel2world(g_width,g_height);
        Vec3f p; bool hit = pick(x,y, pixel2world.l.vx, pixel2world.l.vy, pixel2world.l.vz, pixel2world.p, p);
        if (hit) g_camera.to = p;
      }

    } else {
      clickX = x; clickY = y;
      int modifiers = glutGetModifiers();
      if      (button == GLUT_LEFT_BUTTON && modifiers == GLUT_ACTIVE_SHIFT) mouseMode = 1;
      else if (button == GLUT_MIDDLE_BUTTON) mouseMode = 2;
      else if (button == GLUT_RIGHT_BUTTON ) mouseMode = 3;
      else if (button == GLUT_LEFT_BUTTON  ) mouseMode = 4;

      if (flip14) {
        if (mouseMode == 4) mouseMode = 1;
        else if (mouseMode == 1) mouseMode = 4;
      }
    }
  }

  void motionFunc(int x, int y)
  {
    float dClickX = float(clickX - x), dClickY = float(clickY - y);
    clickX = x; clickY = y;

    switch (mouseMode) {
    case 1: g_camera.rotateOrbit(-0.005f*dClickX,0.005f*dClickY); break;
    case 2: break;
    case 3: g_camera.dolly(-dClickY); break;
    case 4: g_camera.rotate(-0.005f*dClickX,0.005f*dClickY); break;
    }
  }

  /*************************************************************************************************/
  /*                                   Window control                                              */
  /*************************************************************************************************/

  void displayFunc(void)
  {
    AffineSpace3f pixel2world = g_camera.pixel2world(g_width,g_height);

    /* render image using ISPC */
    double t0 = getSeconds();
    render(g_time0-t0,
           pixel2world.l.vx,
           pixel2world.l.vy,
           pixel2world.l.vz,
           pixel2world.p);
    double dt0 = getSeconds()-t0;

    if (g_display)
    {
      /* draw pixels to screen */
      int* pixels = map();
      glRasterPos2i(-1, 1);
      glPixelZoom(1.0f, -1.0f);
      glDrawPixels(g_width,g_height,GL_RGBA,GL_UNSIGNED_BYTE,pixels);
      glutSwapBuffers();
      unmap();
    }
    double dt1 = getSeconds()-t0;

    /* print frame rate */
    std::ostringstream stream;
    stream.setf(std::ios::fixed, std::ios::floatfield);
    stream.precision(2);
    stream << "render: ";
    stream << 1.0f/dt0 << " fps, ";
    stream << dt0*1000.0f << " ms, ";
    stream << "display: ";
    stream << 1.0f/dt1 << " fps, ";
    stream << dt1*1000.0f << " ms, ";
    stream << g_width << "x" << g_height << " pixels";
    std::cout << stream.str() << std::endl;
  }

  void reshapeFunc(int width, int height)
  {
    resize(width,height);
    glViewport(0, 0, width, height);
    g_width = width; g_height = height;
  }

  void idleFunc() {
    glutPostRedisplay();
  }

  /* initialize GLUT */
  void initGlut (const std::string name, const size_t width, const size_t height, const bool fullscreen, const bool mouseMode)
  {
    g_width = width;
    g_height = height;
    resize(g_width,g_height);

    g_fullscreen = fullscreen;
    flip14 = mouseMode;
    int argc = 0; char** argv = NULL;
    glutInit(&argc, argv);
    glutInitWindowSize((GLsizei)g_width, (GLsizei)g_height);
    glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE);
    glutInitWindowPosition(0, 0);
    g_window = glutCreateWindow(name.c_str());
    if (g_fullscreen) glutFullScreen();
    glutDisplayFunc(displayFunc);
    glutIdleFunc(idleFunc);
    glutKeyboardFunc(keyboardFunc);
    glutSpecialFunc(specialFunc);
    glutMouseFunc(clickFunc);
    glutMotionFunc(motionFunc);
    glutReshapeFunc(reshapeFunc);
    glutMainLoop();
  }
}
<|endoftext|>


<commit_before>/*==============================================================================
 * FILE:	   DfaTest.cc
 * OVERVIEW:   Provides the implementation for the DfaTest class, which
 *				tests the data flow based type analysis code
 *============================================================================*/
/*
 * $Revision$
 *
 * 19 Oct 04 - Mike: Created
 */

#include "DfaTest.h"

/*==============================================================================
 * FUNCTION:		DfaTest::registerTests
 * OVERVIEW:		Register the test functions in the given suite
 * PARAMETERS:		Pointer to the test suite
 * RETURNS:			<nothing>
 *============================================================================*/
#define MYTEST(name) \
suite->addTest(new CppUnit::TestCaller<DfaTest> ("DfaTest", \
	&DfaTest::name, *this))

void DfaTest::registerTests(CppUnit::TestSuite* suite) {
	MYTEST(testMeetInt);
	MYTEST(testMeetSize);
	MYTEST(testMeetPointer);
	MYTEST(testMeetUnion);
}

int DfaTest::countTestCases () const
{ return 2; }	// ? What's this for?

/*==============================================================================
 * FUNCTION:		DfaTest::setUp
 * OVERVIEW:		Set up some expressions for use with all the tests
 * NOTE:			Called before any tests
 * PARAMETERS:		<none>
 * RETURNS:			<nothing>
 *============================================================================*/
void DfaTest::setUp () {
}

/*==============================================================================
 * FUNCTION:		DfaTest::tearDown
 * OVERVIEW:		Delete expressions created in setUp
 * NOTE:			Called after all tests
 * PARAMETERS:		<none>
 * RETURNS:			<nothing>
 *============================================================================*/
void DfaTest::tearDown () {
}

/*==============================================================================
 * FUNCTION:		DfaTest::testMeetInt
 * OVERVIEW:		Test meeting IntegerTypes with various other types
 *============================================================================*/
void DfaTest::testMeetInt () {
	IntegerType i32(32, 1);
	IntegerType j32(32, 0);
	IntegerType u32(32, -1);
	IntegerType xint(0);
	IntegerType j16(16, 0);
	SizeType s32(32);
	SizeType s64(64);
	FloatType flt(32);
	PointerType pt(&flt);
	VoidType v;

	bool ch = false;
	i32.meetWith(&i32, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost1;
	ost1<< &i32;
	std::string actual(ost1.str());
	std::string expected("i32");
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	i32.meetWith(&j32, ch);
	CPPUNIT_ASSERT(ch == false);
	j32.meetWith(&i32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost2;
	ost2<< &i32;
	actual = ost2.str();
	expected = "i32";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	j32.setSigned(0);
	j32.meetWith(&v, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost2a;
	ost2a<< &j32;
	actual = ost2a.str();
	expected = "j32";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	j32.meetWith(&u32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost3;
	ost3<< &j32;
	actual = ost3.str();
	expected = "u32";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	u32.meetWith(&s32, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost4;
	ost4<< &u32;
	actual = ost4.str();
	expected = "u32";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	u32.meetWith(&s64, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost5;
	ost5<< &u32;
	actual = ost5.str();
	expected = "u64";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	Type* res = i32.meetWith(&flt, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost6;
	ost6<< res;
	actual = ost6.str();
	expected = "union";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	res = i32.meetWith(&pt, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost7;
	ost7<< res;
	actual = ost7.str();
	expected = "union";
	CPPUNIT_ASSERT_EQUAL(expected, actual);
}

/*==============================================================================
 * FUNCTION:		DfaTest::testMeetSize
 * OVERVIEW:		Test meeting IntegerTypes with various other types
 *============================================================================*/
void DfaTest::testMeetSize () {
	IntegerType i32(32, 1);
	SizeType s32(32);
	SizeType s16(16);
	FloatType flt(32);
	VoidType v;

	bool ch = false;
	Type* res = s32.meetWith(&i32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost1;
	ost1 << res;
	std::string actual(ost1.str());
	std::string expected("i32");
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	res = s32.meetWith(&s16, ch);
	CPPUNIT_ASSERT(ch == false);

	res = s16.meetWith(&flt, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost2;
	ost2 << res;
	actual = ost2.str();
	expected = "union";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	res = s16.meetWith(&v, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost3;
	ost3 << res;
	actual = ost3.str();
	expected = "16";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

}

/*==============================================================================
 * FUNCTION:		DfaTest::testMeetPointer
 * OVERVIEW:		Test meeting IntegerTypes with various other types
 *============================================================================*/
void DfaTest::testMeetPointer() {
	IntegerType i32(32, 1);
	IntegerType u32(32, -1);
	PointerType pi32(&i32);
	PointerType pu32(&u32);
	VoidType v;

	std::ostringstream ost1;
	ost1 << pu32.getCtype();
	std::string actual(ost1.str());
	std::string expected("unsigned int *");
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	bool ch = false;
	Type* res = pi32.meetWith(&pu32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost2;
	ost2 << res->getCtype();
	actual = ost2.str();
	expected = "/*signed?*/int *";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	res = pi32.meetWith(&v, ch);
	CPPUNIT_ASSERT(ch == false);

	res = pi32.meetWith(&i32, ch);
	std::ostringstream ost3;
	ost3 << res;
	actual = ost3.str();
	expected = "union";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

}

/*==============================================================================
 * FUNCTION:		DfaTest::testMeetUnion
 * OVERVIEW:		Test meeting IntegerTypes with various other types
 *============================================================================*/
void DfaTest::testMeetUnion() {
	UnionType u1;
	IntegerType i32(32, 1);
	IntegerType j32(32, 0);
	IntegerType u32(32, -1);
	FloatType flt(32);
	u1.addType(&i32, "bow");
	u1.addType(&flt, "wow");

	std::ostringstream ost1;
	ost1 << u1.getCtype();
	std::string actual(ost1.str());
	std::string expected("union { int bow; float wow; }");
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	bool ch = false;
	Type* res = u1.meetWith(&j32, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost2;
	ost2 << res->getCtype();
	actual = ost2.str();
	expected = "union { int bow; float wow; }";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	res = u1.meetWith(&j32, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost3;
	ost3 << u1.getCtype();
	actual = ost3.str();
	expected = "union { int bow; float wow; }";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	// Note: this test relies on the int in the union having signedness 1
	res = u1.meetWith(&u32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost4;
	ost4 << u1.getCtype();
	actual = ost4.str();
	expected = "union { /*signed?*/int bow; float wow; }";
	CPPUNIT_ASSERT_EQUAL(expected, actual);
}
<commit_msg>Use ErrLogger to warn about known unit test failure<commit_after>/*==============================================================================
 * FILE:	   DfaTest.cc
 * OVERVIEW:   Provides the implementation for the DfaTest class, which
 *				tests the data flow based type analysis code
 *============================================================================*/
/*
 * $Revision$
 *
 * 19 Oct 04 - Mike: Created
 */

#include "DfaTest.h"
#include <iostream>		// For std::cerr
#include <log.h>
#include <boomerang.h>

class ErrLogger : public Log {
public:
	virtual Log &operator<<(const char *str) {
	 std::cerr << str;
		return *this;
	}
	virtual ~ErrLogger() {};
};
/*==============================================================================
 * FUNCTION:		DfaTest::registerTests
 * OVERVIEW:		Register the test functions in the given suite
 * PARAMETERS:		Pointer to the test suite
 * RETURNS:			<nothing>
 *============================================================================*/
#define MYTEST(name) \
suite->addTest(new CppUnit::TestCaller<DfaTest> ("DfaTest", \
	&DfaTest::name, *this))

void DfaTest::registerTests(CppUnit::TestSuite* suite) {
	MYTEST(testMeetInt);
	MYTEST(testMeetSize);
	MYTEST(testMeetPointer);
	MYTEST(testMeetUnion);
}

int DfaTest::countTestCases () const
{ return 2; }	// ? What's this for?

/*==============================================================================
 * FUNCTION:		DfaTest::setUp
 * OVERVIEW:		Set up some expressions for use with all the tests
 * NOTE:			Called before any tests
 * PARAMETERS:		<none>
 * RETURNS:			<nothing>
 *============================================================================*/
void DfaTest::setUp () {
}

/*==============================================================================
 * FUNCTION:		DfaTest::tearDown
 * OVERVIEW:		Delete expressions created in setUp
 * NOTE:			Called after all tests
 * PARAMETERS:		<none>
 * RETURNS:			<nothing>
 *============================================================================*/
void DfaTest::tearDown () {
}

/*==============================================================================
 * FUNCTION:		DfaTest::testMeetInt
 * OVERVIEW:		Test meeting IntegerTypes with various other types
 *============================================================================*/
void DfaTest::testMeetInt () {
	IntegerType i32(32, 1);
	IntegerType j32(32, 0);
	IntegerType u32(32, -1);
	IntegerType xint(0);
	IntegerType j16(16, 0);
	SizeType s32(32);
	SizeType s64(64);
	FloatType flt(32);
	PointerType pt(&flt);
	VoidType v;

	bool ch = false;
	i32.meetWith(&i32, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost1;
	ost1<< &i32;
	std::string actual(ost1.str());
	std::string expected("i32");
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	i32.meetWith(&j32, ch);
	CPPUNIT_ASSERT(ch == false);
	j32.meetWith(&i32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost2;
	ost2<< &i32;
	actual = ost2.str();
	expected = "i32";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	j32.setSigned(0);
	j32.meetWith(&v, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost2a;
	ost2a<< &j32;
	actual = ost2a.str();
	expected = "j32";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	j32.meetWith(&u32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost3;
	ost3<< &j32;
	actual = ost3.str();
	expected = "u32";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	u32.meetWith(&s32, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost4;
	ost4<< &u32;
	actual = ost4.str();
	expected = "u32";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	u32.meetWith(&s64, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost5;
	ost5<< &u32;
	actual = ost5.str();
	expected = "u64";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	Type* res = i32.meetWith(&flt, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost6;
	ost6<< res;
	actual = ost6.str();
	expected = "union";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	res = i32.meetWith(&pt, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost7;
	ost7<< res;
	actual = ost7.str();
	expected = "union";
	CPPUNIT_ASSERT_EQUAL(expected, actual);
}

/*==============================================================================
 * FUNCTION:		DfaTest::testMeetSize
 * OVERVIEW:		Test meeting IntegerTypes with various other types
 *============================================================================*/
void DfaTest::testMeetSize () {
	IntegerType i32(32, 1);
	SizeType s32(32);
	SizeType s16(16);
	FloatType flt(32);
	VoidType v;

	bool ch = false;
	Type* res = s32.meetWith(&i32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost1;
	ost1 << res;
	std::string actual(ost1.str());
	std::string expected("i32");
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	res = s32.meetWith(&s16, ch);
	CPPUNIT_ASSERT(ch == false);

	// There is a known failure here; to show the warning, use ErrLogger
	Boomerang::get()->setLogger(new ErrLogger);

	res = s16.meetWith(&flt, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost2;
	ost2 << res;
	actual = ost2.str();
	expected = "union";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	res = s16.meetWith(&v, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost3;
	ost3 << res;
	actual = ost3.str();
	expected = "16";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

}

/*==============================================================================
 * FUNCTION:		DfaTest::testMeetPointer
 * OVERVIEW:		Test meeting IntegerTypes with various other types
 *============================================================================*/
void DfaTest::testMeetPointer() {
	IntegerType i32(32, 1);
	IntegerType u32(32, -1);
	PointerType pi32(&i32);
	PointerType pu32(&u32);
	VoidType v;

	std::ostringstream ost1;
	ost1 << pu32.getCtype();
	std::string actual(ost1.str());
	std::string expected("unsigned int *");
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	bool ch = false;
	Type* res = pi32.meetWith(&pu32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost2;
	ost2 << res->getCtype();
	actual = ost2.str();
	expected = "/*signed?*/int *";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	ch = false;
	res = pi32.meetWith(&v, ch);
	CPPUNIT_ASSERT(ch == false);

	res = pi32.meetWith(&i32, ch);
	std::ostringstream ost3;
	ost3 << res;
	actual = ost3.str();
	expected = "union";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

}

/*==============================================================================
 * FUNCTION:		DfaTest::testMeetUnion
 * OVERVIEW:		Test meeting IntegerTypes with various other types
 *============================================================================*/
void DfaTest::testMeetUnion() {
	UnionType u1;
	IntegerType i32(32, 1);
	IntegerType j32(32, 0);
	IntegerType u32(32, -1);
	FloatType flt(32);
	u1.addType(&i32, "bow");
	u1.addType(&flt, "wow");

	std::ostringstream ost1;
	ost1 << u1.getCtype();
	std::string actual(ost1.str());
	std::string expected("union { int bow; float wow; }");
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	bool ch = false;
	Type* res = u1.meetWith(&j32, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost2;
	ost2 << res->getCtype();
	actual = ost2.str();
	expected = "union { int bow; float wow; }";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	res = u1.meetWith(&j32, ch);
	CPPUNIT_ASSERT(ch == false);
	std::ostringstream ost3;
	ost3 << u1.getCtype();
	actual = ost3.str();
	expected = "union { int bow; float wow; }";
	CPPUNIT_ASSERT_EQUAL(expected, actual);

	// Note: this test relies on the int in the union having signedness 1
	res = u1.meetWith(&u32, ch);
	CPPUNIT_ASSERT(ch == true);
	std::ostringstream ost4;
	ost4 << u1.getCtype();
	actual = ost4.str();
	expected = "union { /*signed?*/int bow; float wow; }";
	CPPUNIT_ASSERT_EQUAL(expected, actual);
}
<|endoftext|>


<commit_before>#include "d2stringtablewidget.h"

#include <QProgressDialog>
#include <QKeyEvent>
#include <QListWidgetItem>
#include <QAction>

#ifndef QT_NO_DEBUG
#include <QDebug>
#endif

D2StringTableWidget::D2StringTableWidget(QWidget *parent) : QTableWidget(parent), _displayRowHex(false), _addToRowValue(true)
{
    setStyleSheet("QTableWidget::item:!active { selection-background-color: #999999 }");
    horizontalHeader()->
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
        setSectionsClickable
#else
        setClickable
#endif
        (false);
}

void D2StringTableWidget::keyPressEvent(QKeyEvent *keyEvent)
{
    switch (keyEvent->key())
    {
#ifndef Q_OS_MAC
        case Qt::Key_Enter:  // Return (usual Enter) or Enter (on the numpad)
#endif
        case Qt::Key_Return: // starts editing of the current selected cell
            if (state() != QAbstractItemView::EditingState)
                emit itemDoubleClicked(currentItem());
            break;
        // in-place edit
#ifdef Q_OS_MAC
        case Qt::Key_Enter:
#else
        case Qt::Key_F2:
#endif
            editInPlace();
            break;
        case Qt::Key_Home: // Home or Ctrl+Home goes to the first cell
            if (keyEvent->modifiers() == Qt::NoModifier || keyEvent->modifiers() == Qt::ControlModifier)
                setCurrentCell(0, 0, QItemSelectionModel::ClearAndSelect);
            break;
        case Qt::Key_End: // End or Ctrl+End goes to the last cell
            if (keyEvent->modifiers() == Qt::NoModifier || keyEvent->modifiers() == Qt::ControlModifier)
                setCurrentCell(rowCount() - 1, 1, QItemSelectionModel::ClearAndSelect);
            break;
        default:
            QTableWidget::keyPressEvent(keyEvent);
            break;
    }
}

void D2StringTableWidget::deleteItems(bool isClear)
{
    QList<QTableWidgetSelectionRange> ranges(selectedRanges());
    int elementsToDelete = 0;
    for (int i = 0; i < ranges.size(); i++)
        elementsToDelete += ranges.at(i).rowCount();

    // deleting rows is a long process, so progress dialog is shown
    QProgressDialog progress(tr("Deleting selected rows..."), tr("Cancel"), 0, elementsToDelete, this);
    progress.setWindowModality(Qt::WindowModal);
    for (int i = 0, rowShift = 0; i < ranges.size(); ++i)
    {
        const QTableWidgetSelectionRange &range = ranges.at(i);
        if (isClear) // Only Delete pressed, clears selected items
        {
            for (int j = range.topRow(); j <= range.bottomRow(); ++j)
                for (int k = range.leftColumn(); k <= range.rightColumn(); ++k)
                    item(j, k)->setText(QString());
        }
        else // Shift+Delete pressed, removes selected rows
        {
            for (int k = 0; k < range.rowCount(); ++k)
            {
                progress.setValue((i + 1) * k);
                if (progress.wasCanceled())
                    return;

                int row = range.topRow() - rowShift;
                removeRow(row);
                _editedItems.remove(qMakePair<int, int>(row, 0));
                _editedItems.remove(qMakePair<int, int>(row, 1));
            }
            rowShift += range.rowCount();
            emit currentCellChanged(currentRow(), 0, 0, 0);
        }
    }
    progress.setValue(elementsToDelete);

    if (!isClear)
        changeRowHeaderDisplay();
}

void D2StringTableWidget::createRowAt(int row)
{
    insertRow(row);
    setItem(row, 0, new QTableWidgetItem);
    setItem(row, 1, new QTableWidgetItem);
    setCurrentCell(row, 0, QItemSelectionModel::ClearAndSelect);
    emit currentCellChanged(row, 0, 0, 0);
}

void D2StringTableWidget::createNewEntry(int row, const QString &key, const QString &val)
{
    setItem(row, 0, new QTableWidgetItem(key.isEmpty() || key == "\"" ? QString() : key.split('\"', QString::SkipEmptyParts).at(0)));
    setItem(row, 1, new QTableWidgetItem(val.isEmpty() || val == "\"" ? QString() : val.split('\"', QString::SkipEmptyParts).at(0)));
}

void D2StringTableWidget::mousePressEvent(QMouseEvent *mouseEvent)
{
    emit tableGotFocus(parentWidget());
    QTableWidget::mousePressEvent(mouseEvent);

    if (mouseEvent->button() == Qt::RightButton)
        editInPlace();
}

void D2StringTableWidget::clearBackground()
{
    // without blocking cells will become green again immediately
    blockSignals(true);
    foreach (QTableWidgetItem *item, _editedItems)
        item->setBackground(QBrush(Qt::white));
    blockSignals(false);

    _editedItems.clear();
}

void D2StringTableWidget::dropEvent(QDropEvent *event)
{
    QTableWidgetItem *firstDroppedItem = itemAt(event->pos());
    QList<QTableWidgetItem *> droppedItems;
    QStringList oldTexts;
    QTableWidgetSelectionRange range = qobject_cast<QTableWidget *>(event->source())->selectedRanges().at(0);
    for (int i = 0, rows = range.bottomRow() - range.topRow(), cols = range.rightColumn() - range.leftColumn(); i <= rows; ++i)
    {
        for (int j = 0; j <= cols; ++j)
        {
            QTableWidgetItem *anItem = item(firstDroppedItem->row() + i, firstDroppedItem->column() + j);
            droppedItems += anItem;
            oldTexts += anItem->text();
        }
    }

    QTableWidget::dropEvent(event);
    for (int i = 0; i < droppedItems.size(); ++i)
    {
        QTableWidgetItem *anItem = droppedItems.at(i);
        if (anItem->text() != oldTexts.at(i))
            emit itemWasDropped(anItem);
    }
}

void D2StringTableWidget::toggleDisplayHex(bool toggled)
{
    _displayRowHex = toggled;
    changeRowHeaderDisplay();
}

void D2StringTableWidget::changeRowNumberingTo1(bool toggled)
{
    _addToRowValue = toggled;
    changeRowHeaderDisplay();
}

void D2StringTableWidget::changeRowHeaderDisplay()
{
    QStringList rowLabels;
    for (int i = 0; i < rowCount(); ++i)
    {
        int row = i + _addToRowValue;
        QString rowText = QString::number(row);
        if (_displayRowHex)
            rowText += QString(" (0x%2)").arg(row, 0, 16);
#ifdef Q_OS_MAC
        rowText += "  "; // fixes slight text truncation
#endif
        rowLabels += rowText;
    }
    setVerticalHeaderLabels(rowLabels);
}
<commit_msg>clear background of dropped/pasted items on saving<commit_after>#include "d2stringtablewidget.h"

#include <QProgressDialog>
#include <QKeyEvent>
#include <QListWidgetItem>
#include <QAction>

#ifndef QT_NO_DEBUG
#include <QDebug>
#endif

D2StringTableWidget::D2StringTableWidget(QWidget *parent) : QTableWidget(parent), _displayRowHex(false), _addToRowValue(true)
{
    setStyleSheet("QTableWidget::item:!active { selection-background-color: #999999 }");
    horizontalHeader()->
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
        setSectionsClickable
#else
        setClickable
#endif
        (false);
}

void D2StringTableWidget::keyPressEvent(QKeyEvent *keyEvent)
{
    switch (keyEvent->key())
    {
#ifndef Q_OS_MAC
        case Qt::Key_Enter:  // Return (usual Enter) or Enter (on the numpad)
#endif
        case Qt::Key_Return: // starts editing of the current selected cell
            if (state() != QAbstractItemView::EditingState)
                emit itemDoubleClicked(currentItem());
            break;
        // in-place edit
#ifdef Q_OS_MAC
        case Qt::Key_Enter:
#else
        case Qt::Key_F2:
#endif
            editInPlace();
            break;
        case Qt::Key_Home: // Home or Ctrl+Home goes to the first cell
            if (keyEvent->modifiers() == Qt::NoModifier || keyEvent->modifiers() == Qt::ControlModifier)
                setCurrentCell(0, 0, QItemSelectionModel::ClearAndSelect);
            break;
        case Qt::Key_End: // End or Ctrl+End goes to the last cell
            if (keyEvent->modifiers() == Qt::NoModifier || keyEvent->modifiers() == Qt::ControlModifier)
                setCurrentCell(rowCount() - 1, 1, QItemSelectionModel::ClearAndSelect);
            break;
        default:
            QTableWidget::keyPressEvent(keyEvent);
            break;
    }
}

void D2StringTableWidget::deleteItems(bool isClear)
{
    QList<QTableWidgetSelectionRange> ranges(selectedRanges());
    int elementsToDelete = 0;
    for (int i = 0; i < ranges.size(); i++)
        elementsToDelete += ranges.at(i).rowCount();

    // deleting rows is a long process, so progress dialog is shown
    QProgressDialog progress(tr("Deleting selected rows..."), tr("Cancel"), 0, elementsToDelete, this);
    progress.setWindowModality(Qt::WindowModal);
    for (int i = 0, rowShift = 0; i < ranges.size(); ++i)
    {
        const QTableWidgetSelectionRange &range = ranges.at(i);
        if (isClear) // Only Delete pressed, clears selected items
        {
            for (int j = range.topRow(); j <= range.bottomRow(); ++j)
                for (int k = range.leftColumn(); k <= range.rightColumn(); ++k)
                    item(j, k)->setText(QString());
        }
        else // Shift+Delete pressed, removes selected rows
        {
            for (int k = 0; k < range.rowCount(); ++k)
            {
                progress.setValue((i + 1) * k);
                if (progress.wasCanceled())
                    return;

                int row = range.topRow() - rowShift;
                removeRow(row);
                _editedItems.remove(qMakePair<int, int>(row, 0));
                _editedItems.remove(qMakePair<int, int>(row, 1));
            }
            rowShift += range.rowCount();
            emit currentCellChanged(currentRow(), 0, 0, 0);
        }
    }
    progress.setValue(elementsToDelete);

    if (!isClear)
        changeRowHeaderDisplay();
}

void D2StringTableWidget::createRowAt(int row)
{
    insertRow(row);
    setItem(row, 0, new QTableWidgetItem);
    setItem(row, 1, new QTableWidgetItem);
    setCurrentCell(row, 0, QItemSelectionModel::ClearAndSelect);
    emit currentCellChanged(row, 0, 0, 0);
}

void D2StringTableWidget::createNewEntry(int row, const QString &key, const QString &val)
{
    setItem(row, 0, new QTableWidgetItem(key.isEmpty() || key == "\"" ? QString() : key.split('\"', QString::SkipEmptyParts).at(0)));
    setItem(row, 1, new QTableWidgetItem(val.isEmpty() || val == "\"" ? QString() : val.split('\"', QString::SkipEmptyParts).at(0)));
}

void D2StringTableWidget::mousePressEvent(QMouseEvent *mouseEvent)
{
    emit tableGotFocus(parentWidget());
    QTableWidget::mousePressEvent(mouseEvent);

    if (mouseEvent->button() == Qt::RightButton)
        editInPlace();
}

void D2StringTableWidget::clearBackground()
{
    // without blocking cells will become green again immediately
    blockSignals(true);
    foreach (QTableWidgetItem *item, _editedItems)
        item->setBackground(QBrush(Qt::white));
    blockSignals(false);

    _editedItems.clear();
}

void D2StringTableWidget::dropEvent(QDropEvent *event)
{
    QTableWidgetItem *firstDroppedItem = itemAt(event->pos());
    QList<QTableWidgetItem *> droppedItems;
    QStringList oldTexts;
    QTableWidgetSelectionRange range = qobject_cast<QTableWidget *>(event->source())->selectedRanges().at(0);
    for (int i = 0, rows = range.bottomRow() - range.topRow(), cols = range.rightColumn() - range.leftColumn(); i <= rows; ++i)
    {
        for (int j = 0; j <= cols; ++j)
        {
            QTableWidgetItem *anItem = item(firstDroppedItem->row() + i, firstDroppedItem->column() + j);
            droppedItems += anItem;
            oldTexts += anItem->text();
            addEditedItem(anItem);
        }
    }

    QTableWidget::dropEvent(event);
    for (int i = 0; i < droppedItems.size(); ++i)
    {
        QTableWidgetItem *anItem = droppedItems.at(i);
        if (anItem->text() != oldTexts.at(i))
            emit itemWasDropped(anItem);
    }
}

void D2StringTableWidget::toggleDisplayHex(bool toggled)
{
    _displayRowHex = toggled;
    changeRowHeaderDisplay();
}

void D2StringTableWidget::changeRowNumberingTo1(bool toggled)
{
    _addToRowValue = toggled;
    changeRowHeaderDisplay();
}

void D2StringTableWidget::changeRowHeaderDisplay()
{
    QStringList rowLabels;
    for (int i = 0; i < rowCount(); ++i)
    {
        int row = i + _addToRowValue;
        QString rowText = QString::number(row);
        if (_displayRowHex)
            rowText += QString(" (0x%2)").arg(row, 0, 16);
#ifdef Q_OS_MAC
        rowText += "  "; // fixes slight text truncation
#endif
        rowLabels += rowText;
    }
    setVerticalHeaderLabels(rowLabels);
}
<|endoftext|>


<commit_before>/* Copyright (C) 2015 Martin Albrecht
 *               2016 Michael Walter

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

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

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

#include <cstring>
#include <fplll.h>

using namespace std;
using namespace fplll;

enum Test
{
  SVP_ENUM,
  DSVP_ENUM,
  DSVP_REDUCE
};

/**
   @brief Read matrix from `input_filename`.

   @param A
   @param input_filename
   @return
*/

template<class ZT>
void readMatrix(ZZ_mat<ZT> &A, const char *input_filename) {
  istream *is = new ifstream(input_filename);
  *is >> A;
  delete is;
}

/**
   @brief Read vector from `input_filename` into `b`.

   @param b                vector
   @param input_filename   filename
   @return
*/

template<class ZT>
void readVector(vector<Z_NR<ZT> > &b, const char *input_filename) {
  istream *is = new ifstream(input_filename);
  *is >> b;
  delete is;
}

/**
   @brief Test if SVP function returns vector with right norm.

   @param A              input lattice
   @param b              shortest vector
   @return
*/

template<class ZT>
int testSVP(ZZ_mat<ZT> &A, IntVect &b) {
  IntVect solCoord;  // In the LLL-reduced basis
  IntVect solCoord2; // In the initial basis
  IntVect solution;
  IntMatrix u;

  int status = lllReduction(A, u, LLL_DEF_DELTA, LLL_DEF_ETA, LM_WRAPPER, FT_DEFAULT, 0, LLL_DEFAULT);
  if (status != RED_SUCCESS) {
    cerr << "LLL reduction failed: " << getRedStatusStr(status) << endl;
    return status;
  }

  status = shortestVector(A, solCoord, SVPM_PROVED, SVP_DEFAULT);

  if (status != RED_SUCCESS) {
    cerr << "Failure: " << getRedStatusStr(status) << endl;
    return status;
  }

  vectMatrixProduct(solCoord2, solCoord, u);
  vectMatrixProduct(solution, solCoord, A);

  Z_NR<ZT> tmp;
  Z_NR<ZT> norm_s;
  Z_NR<ZT> norm_b;

  for(int i=0; i<A.getCols(); i++) {
    tmp.mul(solution[i], solution[i]);
    norm_s.add(norm_s, tmp);

    tmp.mul(b[i], b[i]);
    norm_b.add(norm_b, tmp);
  }
  if (norm_s != norm_b)
    return 1;

  return 0;
}

/**
   @brief Compute the norm of a dual vector (specified by coefficients in the dual basis).

   @param A              input lattice
   @param b              coefficients of shortest dual vector
   @return
*/
template<class ZT>
int dualLength(Float &norm, ZZ_mat<ZT> &A, const IntVect &coords) {
  int d = coords.size();
  if (A.getRows() != d) {
    cerr << "DSVP length error: Coefficient vector has wrong dimension: ";
    cerr << A.getRows() << " vs " << d << endl;
    return 1;
  }
  FloatVect coords_d(d);
  for (int i = 0; i < d; i++) {
    coords_d[i] = coords[i].get_d();
  }

  IntMatrix emptyMat;
  MatGSO<Integer, Float> gso(A, emptyMat, emptyMat, GSO_INT_GRAM);
  if (!gso.updateGSO()) {
    cerr << "GSO Failure." << endl;
    return 1;
  }
  Float tmp;
  gso.getR(tmp, d-1, d-1);
  tmp.pow_si(tmp, -1);

  FloatVect alpha(d);
  Float mu, alpha2, r_inv;
  norm = 0;
  for (int i = 0; i < d; i++) {
    alpha[i] = coords_d[i];
    for (int j = 0; j < i; j++) {
      gso.getMu(mu, i, j);
      alpha[i] -= mu*alpha[j];
    }
    gso.getR(r_inv, i, i);
    r_inv.pow_si(r_inv, -1);
    alpha2.pow_si(alpha[i], 2);
    norm += alpha2 * r_inv;
  }

  return 0;
}

/**
   @brief Test if dual SVP function returns vector with right norm.

   @param A              input lattice
   @param b              shortest dual vector
   @return
*/

template<class ZT>
int testDualSVP(ZZ_mat<ZT> &A, IntVect &b) {
  IntVect solCoord;  // In the LLL-reduced basis
  IntVect solution;
  IntMatrix u;

  Float normb;
  if (dualLength(normb, A, b)) {
    return 1;
  }

  int status = lllReduction(A, u, LLL_DEF_DELTA, LLL_DEF_ETA, LM_WRAPPER, FT_DEFAULT, 0, LLL_DEFAULT);
  if (status != RED_SUCCESS) {
    cerr << "LLL reduction failed: " << getRedStatusStr(status) << endl;
    return status;
  }

  status = shortestVector(A, solCoord, SVPM_FAST, SVP_DUAL);

  if (status != RED_SUCCESS) {
    cerr << "Failure: " << getRedStatusStr(status) << endl;
    return status;
  }

  Float normSol;
  if (dualLength(normSol, A, solCoord)) {
    return 1;
  }

  Float error; error = 1;
  error.mul_2si(error, -(int)error.getprec());
  normb += error;
  if (normSol > normb) {
    cerr << "Returned dual vector too long by more than " << error << endl;
    return 1;
  }

  return 0;
}

/**
   @brief Test if dual SVP reduction returns reduced basis.

   @param A              input lattice
   @param b              shortest dual vector
   @return
*/
template<class ZT>
int testDSVPReduce(ZZ_mat<ZT> &A, IntVect &b) {
  IntMatrix u;
  int d = A.getRows();

  Float normb;
  if (dualLength(normb, A, b)) {
    return 1;
  }

  int status = lllReduction(A, u, LLL_DEF_DELTA, LLL_DEF_ETA, LM_WRAPPER, FT_DEFAULT, 0, LLL_DEFAULT);
  if (status != RED_SUCCESS) {
    cerr << "LLL reduction failed: " << getRedStatusStr(status) << endl;
    return status;
  }

  IntMatrix emptyMat;
  MatGSO<Integer, Float> gso(A, emptyMat, emptyMat, GSO_INT_GRAM);
  LLLReduction<Integer, Float> lllObj(gso, LLL_DEF_DELTA, LLL_DEF_ETA, LLL_DEFAULT);

  vector<Strategy> strategies;
  BKZParam dummy(d, strategies);
  BKZReduction<Float> bkzObj(gso, lllObj, dummy);
  bool clean = true;

  bkzObj.svp_reduction_ex(0, d, dummy, clean, true);
  status = bkzObj.status;
  if (status != RED_SUCCESS) {
    cerr << "Failure: " << getRedStatusStr(status) << endl;
    return status;
  }

  Float normSol;
  Integer zero; zero = 0;
  IntVect e_n(d, zero);
  e_n[d-1] = 1;
  if (dualLength(normSol, A, e_n)) {
    return 1;
  }

  Float error; error = 1;
  error.mul_2si(error, -(int)error.getprec());
  normb += error;
  if (normSol > normb) {
    cerr << "Last dual vector too long by more than " << error << endl;
    return 1;
  }

  return 0;
}

/**
   @brief Test if SVP function returns vector with right norm.

   @param input_filename   filename of an input lattice
   @param output_filename  filename of a shortest vector
   @return
*/

template<class ZT>
int testFilename(const char *input_filename, const char *output_filename, const Test test = SVP_ENUM) {
  ZZ_mat<ZT> A;
  readMatrix(A, input_filename);

  IntVect b;
  readVector(b, output_filename);

  switch(test) {
    case SVP_ENUM     : return testSVP<ZT>(A, b);
    case DSVP_ENUM    : return testDualSVP<ZT>(A, b);
    case DSVP_REDUCE  : return testDSVPReduce<ZT>(A, b);
  }

  cerr << "Unknown test." << endl;
  return 1;
}

/**
   @brief Run SVP tests.

   @param argc             ignored
   @param argv             ignored
   @return
*/

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

  int status = 0;
  status |= testFilename<mpz_t>("lattices/example_svp_in", "lattices/example_svp_out");
  status |= testFilename<mpz_t>("lattices/example_dsvp_in", "lattices/example_dsvp_out", DSVP_ENUM);
  status |= testFilename<mpz_t>("lattices/example_dsvp_in", "lattices/example_dsvp_out", DSVP_REDUCE);

  if (status == 0) {
    cerr << "All tests passed." << endl;
    return 0;
  } else {
    return -1;
  }

  return 0;
}
<commit_msg>CamelCase to lower_case<commit_after>/* Copyright (C) 2015 Martin Albrecht
 *               2016 Michael Walter

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

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

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

#include <cstring>
#include <fplll.h>

using namespace std;
using namespace fplll;

enum Test
{
  SVP_ENUM,
  DSVP_ENUM,
  DSVP_REDUCE
};

/**
   @brief Read matrix from `input_filename`.

   @param A
   @param input_filename
   @return
*/

template<class ZT>
void read_matrix(ZZ_mat<ZT> &A, const char *input_filename) {
  istream *is = new ifstream(input_filename);
  *is >> A;
  delete is;
}

/**
   @brief Read vector from `input_filename` into `b`.

   @param b                vector
   @param input_filename   filename
   @return
*/

template<class ZT>
void read_vector(vector<Z_NR<ZT> > &b, const char *input_filename) {
  istream *is = new ifstream(input_filename);
  *is >> b;
  delete is;
}

/**
   @brief Test if SVP function returns vector with right norm.

   @param A              input lattice
   @param b              shortest vector
   @return
*/

template<class ZT>
int test_svp(ZZ_mat<ZT> &A, IntVect &b) {
  IntVect sol_coord;  // In the LLL-reduced basis
  IntVect sol_coord2; // In the initial basis
  IntVect solution;
  IntMatrix u;

  int status = lllReduction(A, u, LLL_DEF_DELTA, LLL_DEF_ETA, LM_WRAPPER, FT_DEFAULT, 0, LLL_DEFAULT);
  if (status != RED_SUCCESS) {
    cerr << "LLL reduction failed: " << getRedStatusStr(status) << endl;
    return status;
  }

  status = shortestVector(A, sol_coord, SVPM_PROVED, SVP_DEFAULT);

  if (status != RED_SUCCESS) {
    cerr << "Failure: " << getRedStatusStr(status) << endl;
    return status;
  }

  vectMatrixProduct(sol_coord2, sol_coord, u);
  vectMatrixProduct(solution, sol_coord, A);

  Z_NR<ZT> tmp;
  Z_NR<ZT> norm_s;
  Z_NR<ZT> norm_b;

  for(int i=0; i<A.getCols(); i++) {
    tmp.mul(solution[i], solution[i]);
    norm_s.add(norm_s, tmp);

    tmp.mul(b[i], b[i]);
    norm_b.add(norm_b, tmp);
  }
  if (norm_s != norm_b)
    return 1;

  return 0;
}

/**
   @brief Compute the norm of a dual vector (specified by coefficients in the dual basis).

   @param A              input lattice
   @param b              coefficients of shortest dual vector
   @return
*/
template<class ZT>
int dual_length(Float &norm, ZZ_mat<ZT> &A, const IntVect &coords) {
  int d = coords.size();
  if (A.getRows() != d) {
    cerr << "DSVP length error: Coefficient vector has wrong dimension: ";
    cerr << A.getRows() << " vs " << d << endl;
    return 1;
  }
  FloatVect coords_d(d);
  for (int i = 0; i < d; i++) {
    coords_d[i] = coords[i].get_d();
  }

  IntMatrix emptyMat;
  MatGSO<Integer, Float> gso(A, emptyMat, emptyMat, GSO_INT_GRAM);
  if (!gso.updateGSO()) {
    cerr << "GSO Failure." << endl;
    return 1;
  }
  Float tmp;
  gso.getR(tmp, d-1, d-1);
  tmp.pow_si(tmp, -1);

  FloatVect alpha(d);
  Float mu, alpha2, r_inv;
  norm = 0;
  for (int i = 0; i < d; i++) {
    alpha[i] = coords_d[i];
    for (int j = 0; j < i; j++) {
      gso.getMu(mu, i, j);
      alpha[i] -= mu*alpha[j];
    }
    gso.getR(r_inv, i, i);
    r_inv.pow_si(r_inv, -1);
    alpha2.pow_si(alpha[i], 2);
    norm += alpha2 * r_inv;
  }

  return 0;
}

/**
   @brief Test if dual SVP function returns vector with right norm.

   @param A              input lattice
   @param b              shortest dual vector
   @return
*/

template<class ZT>
int test_dual_svp(ZZ_mat<ZT> &A, IntVect &b) {
  IntVect solCoord;  // In the LLL-reduced basis
  IntVect solution;
  IntMatrix u;

  Float normb;
  if (dual_length(normb, A, b)) {
    return 1;
  }

  int status = lllReduction(A, u, LLL_DEF_DELTA, LLL_DEF_ETA, LM_WRAPPER, FT_DEFAULT, 0, LLL_DEFAULT);
  if (status != RED_SUCCESS) {
    cerr << "LLL reduction failed: " << getRedStatusStr(status) << endl;
    return status;
  }

  status = shortestVector(A, solCoord, SVPM_FAST, SVP_DUAL);

  if (status != RED_SUCCESS) {
    cerr << "Failure: " << getRedStatusStr(status) << endl;
    return status;
  }

  Float norm_sol;
  if (dual_length(norm_sol, A, solCoord)) {
    return 1;
  }

  Float error; error = 1;
  error.mul_2si(error, -(int)error.getprec());
  normb += error;
  if (norm_sol > normb) {
    cerr << "Returned dual vector too long by more than " << error << endl;
    return 1;
  }

  return 0;
}

/**
   @brief Test if dual SVP reduction returns reduced basis.

   @param A              input lattice
   @param b              shortest dual vector
   @return
*/
template<class ZT>
int test_dsvp_reduce(ZZ_mat<ZT> &A, IntVect &b) {
  IntMatrix u;
  int d = A.getRows();

  Float normb;
  if (dual_length(normb, A, b)) {
    return 1;
  }

  int status = lllReduction(A, u, LLL_DEF_DELTA, LLL_DEF_ETA, LM_WRAPPER, FT_DEFAULT, 0, LLL_DEFAULT);
  if (status != RED_SUCCESS) {
    cerr << "LLL reduction failed: " << getRedStatusStr(status) << endl;
    return status;
  }

  IntMatrix empty_mat;
  MatGSO<Integer, Float> gso(A, empty_mat, empty_mat, GSO_INT_GRAM);
  LLLReduction<Integer, Float> lll_obj(gso, LLL_DEF_DELTA, LLL_DEF_ETA, LLL_DEFAULT);

  vector<Strategy> strategies;
  BKZParam dummy(d, strategies);
  BKZReduction<Float> bkz_obj(gso, lll_obj, dummy);
  bool clean = true;

  bkz_obj.svp_reduction_ex(0, d, dummy, clean, true);
  status = bkz_obj.status;
  if (status != RED_SUCCESS) {
    cerr << "Failure: " << getRedStatusStr(status) << endl;
    return status;
  }

  Float norm_sol;
  Integer zero; zero = 0;
  IntVect e_n(d, zero);
  e_n[d-1] = 1;
  if (dual_length(norm_sol, A, e_n)) {
    return 1;
  }

  Float error; error = 1;
  error.mul_2si(error, -(int)error.getprec());
  normb += error;
  if (norm_sol > normb) {
    cerr << "Last dual vector too long by more than " << error << endl;
    return 1;
  }

  return 0;
}

/**
   @brief Test if SVP function returns vector with right norm.

   @param input_filename   filename of an input lattice
   @param output_filename  filename of a shortest vector
   @return
*/

template<class ZT>
int test_filename(const char *input_filename, const char *output_filename, const Test test = SVP_ENUM) {
  ZZ_mat<ZT> A;
  read_matrix(A, input_filename);

  IntVect b;
  read_vector(b, output_filename);

  switch(test) {
    case SVP_ENUM     : return test_svp<ZT>(A, b);
    case DSVP_ENUM    : return test_dual_svp<ZT>(A, b);
    case DSVP_REDUCE  : return test_dsvp_reduce<ZT>(A, b);
  }

  cerr << "Unknown test." << endl;
  return 1;
}

/**
   @brief Run SVP tests.

   @param argc             ignored
   @param argv             ignored
   @return
*/

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

  int status = 0;
  status |= test_filename<mpz_t>("lattices/example_svp_in", "lattices/example_svp_out");
  status |= test_filename<mpz_t>("lattices/example_dsvp_in", "lattices/example_dsvp_out", DSVP_ENUM);
  status |= test_filename<mpz_t>("lattices/example_dsvp_in", "lattices/example_dsvp_out", DSVP_REDUCE);

  if (status == 0) {
    cerr << "All tests passed." << endl;
    return 0;
  } else {
    return -1;
  }

  return 0;
}
<|endoftext|>


<commit_before>//===- Driver.cpp ---------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Config.h"
#include "Driver.h"
#include "InputFiles.h"
#include "Memory.h"
#include "SymbolTable.h"
#include "Writer.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>

using namespace llvm;
using llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
using llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI;
using llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI;
using llvm::sys::Process;
using llvm::sys::fs::file_magic;
using llvm::sys::fs::identify_magic;

namespace lld {
namespace coff {

Configuration *Config;
LinkerDriver *Driver;

bool link(int Argc, const char *Argv[]) {
  auto C = make_unique<Configuration>();
  Config = C.get();
  auto D = make_unique<LinkerDriver>();
  Driver = D.get();
  return Driver->link(Argc, Argv);
}

static std::string getOutputPath(llvm::opt::InputArgList *Args) {
  if (auto *Arg = Args->getLastArg(OPT_out))
    return Arg->getValue();
  for (auto *Arg : Args->filtered(OPT_INPUT)) {
    if (!StringRef(Arg->getValue()).endswith_lower(".obj"))
      continue;
    SmallString<128> Val = StringRef(Arg->getValue());
    llvm::sys::path::replace_extension(Val, ".exe");
    return Val.str();
  }
  llvm_unreachable("internal error");
}

// Opens a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
ErrorOr<std::unique_ptr<InputFile>> LinkerDriver::openFile(StringRef Path) {
  auto MBOrErr = MemoryBuffer::getFile(Path);
  if (auto EC = MBOrErr.getError())
    return EC;
  std::unique_ptr<MemoryBuffer> MB = std::move(MBOrErr.get());
  MemoryBufferRef MBRef = MB->getMemBufferRef();
  OwningMBs.push_back(std::move(MB)); // take ownership

  // File type is detected by contents, not by file extension.
  file_magic Magic = identify_magic(MBRef.getBuffer());
  if (Magic == file_magic::archive)
    return std::unique_ptr<InputFile>(new ArchiveFile(MBRef));
  if (Magic == file_magic::bitcode)
    return std::unique_ptr<InputFile>(new BitcodeFile(MBRef));
  return std::unique_ptr<InputFile>(new ObjectFile(MBRef));
}

namespace {
class BumpPtrStringSaver : public llvm::cl::StringSaver {
public:
  BumpPtrStringSaver(lld::coff::StringAllocator *A) : Alloc(A) {}
  const char *SaveString(const char *S) override {
    return Alloc->save(S).data();
  }
  lld::coff::StringAllocator *Alloc;
};
}

// Parses .drectve section contents and returns a list of files
// specified by /defaultlib.
std::error_code
LinkerDriver::parseDirectives(StringRef S,
                              std::vector<std::unique_ptr<InputFile>> *Res) {
  SmallVector<const char *, 16> Tokens;
  Tokens.push_back("link"); // argv[0] value. Will be ignored.
  BumpPtrStringSaver Saver(&Alloc);
  llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens);
  Tokens.push_back(nullptr);
  int Argc = Tokens.size() - 1;
  const char **Argv = &Tokens[0];

  auto ArgsOrErr = parseArgs(Argc, Argv);
  if (auto EC = ArgsOrErr.getError())
    return EC;
  std::unique_ptr<llvm::opt::InputArgList> Args = std::move(ArgsOrErr.get());

  for (auto *Arg : Args->filtered(OPT_defaultlib)) {
    if (Optional<StringRef> Path = findLib(Arg->getValue())) {
      auto FileOrErr = openFile(*Path);
      if (auto EC = FileOrErr.getError())
        return EC;
      std::unique_ptr<InputFile> File = std::move(FileOrErr.get());
      Res->push_back(std::move(File));
    }
  }
  return std::error_code();
}

// Find file from search paths. You can omit ".obj", this function takes
// care of that. Note that the returned path is not guaranteed to exist.
StringRef LinkerDriver::doFindFile(StringRef Filename) {
  bool hasPathSep = (Filename.find_first_of("/\\") != StringRef::npos);
  if (hasPathSep)
    return Filename;
  bool hasExt = (Filename.find('.') != StringRef::npos);
  for (StringRef Dir : SearchPaths) {
    SmallString<128> Path = Dir;
    llvm::sys::path::append(Path, Filename);
    if (llvm::sys::fs::exists(Path.str()))
      return Alloc.save(Path.str());
    if (!hasExt) {
      Path.append(".obj");
      if (llvm::sys::fs::exists(Path.str()))
        return Alloc.save(Path.str());
    }
  }
  return Filename;
}

// Resolves a file path. This never returns the same path
// (in that case, it returns None).
Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
  StringRef Path = doFindFile(Filename);
  bool Seen = !VisitedFiles.insert(Path.lower()).second;
  if (Seen)
    return None;
  return Path;
}

// Find library file from search path.
StringRef LinkerDriver::doFindLib(StringRef Filename) {
  // Add ".lib" to Filename if that has no file extension.
  bool hasExt = (Filename.find('.') != StringRef::npos);
  if (!hasExt)
    Filename = Alloc.save(Filename + ".lib");
  return doFindFile(Filename);
}

// Resolves a library path. /nodefaultlib options are taken into
// consideration. This never returns the same path (in that case,
// it returns None).
Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
  if (Config->NoDefaultLibAll)
    return None;
  StringRef Path = doFindLib(Filename);
  if (Config->NoDefaultLibs.count(Path))
    return None;
  bool Seen = !VisitedFiles.insert(Path.lower()).second;
  if (Seen)
    return None;
  return Path;
}

// Parses LIB environment which contains a list of search paths.
std::vector<StringRef> LinkerDriver::getSearchPaths() {
  std::vector<StringRef> Ret;
  Ret.push_back(".");
  Optional<std::string> EnvOpt = Process::GetEnv("LIB");
  if (!EnvOpt.hasValue())
    return Ret;
  StringRef Env = Alloc.save(*EnvOpt);
  while (!Env.empty()) {
    StringRef Path;
    std::tie(Path, Env) = Env.split(';');
    Ret.push_back(Path);
  }
  return Ret;
}

bool LinkerDriver::link(int Argc, const char *Argv[]) {
  // Needed for LTO.
  llvm::InitializeAllTargetInfos();
  llvm::InitializeAllTargets();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllAsmParsers();
  llvm::InitializeAllAsmPrinters();
  llvm::InitializeAllDisassemblers();

  // Parse command line options.
  auto ArgsOrErr = parseArgs(Argc, Argv);
  if (auto EC = ArgsOrErr.getError()) {
    llvm::errs() << EC.message() << "\n";
    return false;
  }
  std::unique_ptr<llvm::opt::InputArgList> Args = std::move(ArgsOrErr.get());

  // Handle /help
  if (Args->hasArg(OPT_help)) {
    printHelp(Argv[0]);
    return true;
  }

  if (Args->filtered_begin(OPT_INPUT) == Args->filtered_end()) {
    llvm::errs() << "no input files.\n";
    return false;
  }

  // Handle /verbose
  if (Args->hasArg(OPT_verbose))
    Config->Verbose = true;

  // Handle /entry
  if (auto *Arg = Args->getLastArg(OPT_entry))
    Config->EntryName = Arg->getValue();

  // Handle /machine
  auto MTOrErr = getMachineType(Args.get());
  if (auto EC = MTOrErr.getError()) {
    llvm::errs() << EC.message() << "\n";
    return false;
  }
  Config->MachineType = MTOrErr.get();

  // Handle /libpath
  for (auto *Arg : Args->filtered(OPT_libpath)) {
    // Inserting at front of a vector is okay because it's short.
    // +1 because the first entry is always "." (current directory).
    SearchPaths.insert(SearchPaths.begin() + 1, Arg->getValue());
  }

  // Handle /nodefaultlib:<filename>
  for (auto *Arg : Args->filtered(OPT_nodefaultlib))
    Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));

  // Handle /nodefaultlib
  if (Args->hasArg(OPT_nodefaultlib_all))
    Config->NoDefaultLibAll = true;

  // Handle /base
  if (auto *Arg = Args->getLastArg(OPT_base)) {
    if (auto EC = parseNumbers(Arg->getValue(), &Config->ImageBase)) {
      llvm::errs() << "/base: " << EC.message() << "\n";
      return false;
    }
  }

  // Handle /stack
  if (auto *Arg = Args->getLastArg(OPT_stack)) {
    if (auto EC = parseNumbers(Arg->getValue(), &Config->StackReserve,
                               &Config->StackCommit)) {
      llvm::errs() << "/stack: " << EC.message() << "\n";
      return false;
    }
  }

  // Handle /heap
  if (auto *Arg = Args->getLastArg(OPT_heap)) {
    if (auto EC = parseNumbers(Arg->getValue(), &Config->HeapReserve,
                               &Config->HeapCommit)) {
      llvm::errs() << "/heap: " << EC.message() << "\n";
      return false;
    }
  }

  // Handle /version
  if (auto *Arg = Args->getLastArg(OPT_version)) {
    if (auto EC = parseVersion(Arg->getValue(), &Config->MajorImageVersion,
                               &Config->MinorImageVersion)) {
      llvm::errs() << "/version: " << EC.message() << "\n";
      return false;
    }
  }

  // Handle /subsystem
  if (auto *Arg = Args->getLastArg(OPT_subsystem)) {
    if (auto EC = parseSubsystem(Arg->getValue(), &Config->Subsystem,
                                 &Config->MajorOSVersion,
                                 &Config->MinorOSVersion)) {
      llvm::errs() << "/subsystem: " << EC.message() << "\n";
      return false;
    }
  }

  // Create a list of input files. Files can be given as arguments
  // for /defaultlib option.
  std::vector<StringRef> Inputs;
  for (auto *Arg : Args->filtered(OPT_INPUT))
    if (Optional<StringRef> Path = findFile(Arg->getValue()))
      Inputs.push_back(*Path);
  for (auto *Arg : Args->filtered(OPT_defaultlib))
    if (Optional<StringRef> Path = findLib(Arg->getValue()))
      Inputs.push_back(*Path);

  // Create a symbol table.
  SymbolTable Symtab;

  // Add undefined symbols given via the command line.
  // (/include is equivalent to Unix linker's -u option.)
  for (auto *Arg : Args->filtered(OPT_incl)) {
    StringRef Sym = Arg->getValue();
    Symtab.addUndefined(Sym);
    Config->GCRoots.insert(Sym);
  }

  // Parse all input files and put all symbols to the symbol table.
  // The symbol table will take care of name resolution.
  for (StringRef Path : Inputs) {
    auto FileOrErr = openFile(Path);
    if (auto EC = FileOrErr.getError()) {
      llvm::errs() << Path << ": " << EC.message() << "\n";
      return false;
    }
    std::unique_ptr<InputFile> File = std::move(FileOrErr.get());
    if (auto EC = Symtab.addFile(std::move(File))) {
      llvm::errs() << Path << ": " << EC.message() << "\n";
      return false;
    }
  }

  // Add weak aliases. Weak aliases is a mechanism to give remaining
  // undefined symbols final chance to be resolved successfully.
  // This is symbol renaming.
  for (auto *Arg : Args->filtered(OPT_alternatename)) {
    StringRef From, To;
    std::tie(From, To) = StringRef(Arg->getValue()).split('=');
    if (From.empty() || To.empty()) {
      llvm::errs() << "/alternatename: invalid argument: "
                   << Arg->getValue() << "\n";
      return false;
    }
    // If it's already resolved as some Defined type, do nothing.
    // Otherwise, rename it to see if To can be resolved instead.
    if (Symtab.find(From))
      continue;
    if (auto EC = Symtab.rename(From, To)) {
      llvm::errs() << EC.message() << "\n";
      return false;
    }
  }

  // Windows specific -- If entry point name is not given, we need to
  // infer that from user-defined entry name. The symbol table takes
  // care of details.
  if (Config->EntryName.empty()) {
    auto EntryOrErr = Symtab.findDefaultEntry();
    if (auto EC = EntryOrErr.getError()) {
      llvm::errs() << EC.message() << "\n";
      return false;
    }
    Config->EntryName = EntryOrErr.get();
  }
  Config->GCRoots.insert(Config->EntryName);

  // Make sure we have resolved all symbols.
  if (Symtab.reportRemainingUndefines())
    return false;

  // Do LTO by compiling bitcode input files to a native COFF file
  // then link that file.
  if (auto EC = Symtab.addCombinedLTOObject()) {
    llvm::errs() << EC.message() << "\n";
    return false;
  }

  // /include option takes precedence over garbage collection.
  for (auto *Arg : Args->filtered(OPT_incl))
    Symtab.find(Arg->getValue())->markLive();

  // Windows specific -- if no /subsystem is given, we need to infer
  // that from entry point name.
  if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
    Config->Subsystem =
      StringSwitch<WindowsSubsystem>(Config->EntryName)
          .Case("mainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_CUI)
          .Case("wmainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_CUI)
          .Case("WinMainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_GUI)
          .Case("wWinMainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_GUI)
          .Default(IMAGE_SUBSYSTEM_UNKNOWN);
    if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
      llvm::errs() << "subsystem must be defined\n";
      return false;
    }
  }

  // Write the result.
  Writer Out(&Symtab);
  if (auto EC = Out.write(getOutputPath(Args.get()))) {
    llvm::errs() << EC.message() << "\n";
    return false;
  }
  return true;
}

} // namespace coff
} // namespace lld
<commit_msg>Add comments.<commit_after>//===- Driver.cpp ---------------------------------------------------------===//
//
//                             The LLVM Linker
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "Config.h"
#include "Driver.h"
#include "InputFiles.h"
#include "Memory.h"
#include "SymbolTable.h"
#include "Writer.h"
#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Option/Arg.h"
#include "llvm/Option/ArgList.h"
#include "llvm/Option/Option.h"
#include "llvm/Support/CommandLine.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/Process.h"
#include "llvm/Support/TargetSelect.h"
#include "llvm/Support/raw_ostream.h"
#include <memory>

using namespace llvm;
using llvm::COFF::IMAGE_SUBSYSTEM_UNKNOWN;
using llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_CUI;
using llvm::COFF::IMAGE_SUBSYSTEM_WINDOWS_GUI;
using llvm::sys::Process;
using llvm::sys::fs::file_magic;
using llvm::sys::fs::identify_magic;

namespace lld {
namespace coff {

Configuration *Config;
LinkerDriver *Driver;

bool link(int Argc, const char *Argv[]) {
  auto C = make_unique<Configuration>();
  Config = C.get();
  auto D = make_unique<LinkerDriver>();
  Driver = D.get();
  return Driver->link(Argc, Argv);
}

static std::string getOutputPath(llvm::opt::InputArgList *Args) {
  if (auto *Arg = Args->getLastArg(OPT_out))
    return Arg->getValue();
  for (auto *Arg : Args->filtered(OPT_INPUT)) {
    if (!StringRef(Arg->getValue()).endswith_lower(".obj"))
      continue;
    SmallString<128> Val = StringRef(Arg->getValue());
    llvm::sys::path::replace_extension(Val, ".exe");
    return Val.str();
  }
  llvm_unreachable("internal error");
}

// Opens a file. Path has to be resolved already.
// Newly created memory buffers are owned by this driver.
ErrorOr<std::unique_ptr<InputFile>> LinkerDriver::openFile(StringRef Path) {
  auto MBOrErr = MemoryBuffer::getFile(Path);
  if (auto EC = MBOrErr.getError())
    return EC;
  std::unique_ptr<MemoryBuffer> MB = std::move(MBOrErr.get());
  MemoryBufferRef MBRef = MB->getMemBufferRef();
  OwningMBs.push_back(std::move(MB)); // take ownership

  // File type is detected by contents, not by file extension.
  file_magic Magic = identify_magic(MBRef.getBuffer());
  if (Magic == file_magic::archive)
    return std::unique_ptr<InputFile>(new ArchiveFile(MBRef));
  if (Magic == file_magic::bitcode)
    return std::unique_ptr<InputFile>(new BitcodeFile(MBRef));
  return std::unique_ptr<InputFile>(new ObjectFile(MBRef));
}

namespace {
class BumpPtrStringSaver : public llvm::cl::StringSaver {
public:
  BumpPtrStringSaver(lld::coff::StringAllocator *A) : Alloc(A) {}
  const char *SaveString(const char *S) override {
    return Alloc->save(S).data();
  }
  lld::coff::StringAllocator *Alloc;
};
}

// Parses .drectve section contents and returns a list of files
// specified by /defaultlib.
std::error_code
LinkerDriver::parseDirectives(StringRef S,
                              std::vector<std::unique_ptr<InputFile>> *Res) {
  SmallVector<const char *, 16> Tokens;
  Tokens.push_back("link"); // argv[0] value. Will be ignored.
  BumpPtrStringSaver Saver(&Alloc);
  llvm::cl::TokenizeWindowsCommandLine(S, Saver, Tokens);
  Tokens.push_back(nullptr);
  int Argc = Tokens.size() - 1;
  const char **Argv = &Tokens[0];

  auto ArgsOrErr = parseArgs(Argc, Argv);
  if (auto EC = ArgsOrErr.getError())
    return EC;
  std::unique_ptr<llvm::opt::InputArgList> Args = std::move(ArgsOrErr.get());

  for (auto *Arg : Args->filtered(OPT_defaultlib)) {
    if (Optional<StringRef> Path = findLib(Arg->getValue())) {
      auto FileOrErr = openFile(*Path);
      if (auto EC = FileOrErr.getError())
        return EC;
      std::unique_ptr<InputFile> File = std::move(FileOrErr.get());
      Res->push_back(std::move(File));
    }
  }
  return std::error_code();
}

// Find file from search paths. You can omit ".obj", this function takes
// care of that. Note that the returned path is not guaranteed to exist.
StringRef LinkerDriver::doFindFile(StringRef Filename) {
  bool hasPathSep = (Filename.find_first_of("/\\") != StringRef::npos);
  if (hasPathSep)
    return Filename;
  bool hasExt = (Filename.find('.') != StringRef::npos);
  for (StringRef Dir : SearchPaths) {
    SmallString<128> Path = Dir;
    llvm::sys::path::append(Path, Filename);
    if (llvm::sys::fs::exists(Path.str()))
      return Alloc.save(Path.str());
    if (!hasExt) {
      Path.append(".obj");
      if (llvm::sys::fs::exists(Path.str()))
        return Alloc.save(Path.str());
    }
  }
  return Filename;
}

// Resolves a file path. This never returns the same path
// (in that case, it returns None).
Optional<StringRef> LinkerDriver::findFile(StringRef Filename) {
  StringRef Path = doFindFile(Filename);
  bool Seen = !VisitedFiles.insert(Path.lower()).second;
  if (Seen)
    return None;
  return Path;
}

// Find library file from search path.
StringRef LinkerDriver::doFindLib(StringRef Filename) {
  // Add ".lib" to Filename if that has no file extension.
  bool hasExt = (Filename.find('.') != StringRef::npos);
  if (!hasExt)
    Filename = Alloc.save(Filename + ".lib");
  return doFindFile(Filename);
}

// Resolves a library path. /nodefaultlib options are taken into
// consideration. This never returns the same path (in that case,
// it returns None).
Optional<StringRef> LinkerDriver::findLib(StringRef Filename) {
  if (Config->NoDefaultLibAll)
    return None;
  StringRef Path = doFindLib(Filename);
  if (Config->NoDefaultLibs.count(Path))
    return None;
  bool Seen = !VisitedFiles.insert(Path.lower()).second;
  if (Seen)
    return None;
  return Path;
}

// Parses LIB environment which contains a list of search paths.
std::vector<StringRef> LinkerDriver::getSearchPaths() {
  std::vector<StringRef> Ret;
  Ret.push_back(".");
  Optional<std::string> EnvOpt = Process::GetEnv("LIB");
  if (!EnvOpt.hasValue())
    return Ret;
  StringRef Env = Alloc.save(*EnvOpt);
  while (!Env.empty()) {
    StringRef Path;
    std::tie(Path, Env) = Env.split(';');
    Ret.push_back(Path);
  }
  return Ret;
}

bool LinkerDriver::link(int Argc, const char *Argv[]) {
  // Needed for LTO.
  llvm::InitializeAllTargetInfos();
  llvm::InitializeAllTargets();
  llvm::InitializeAllTargetMCs();
  llvm::InitializeAllAsmParsers();
  llvm::InitializeAllAsmPrinters();
  llvm::InitializeAllDisassemblers();

  // Parse command line options.
  auto ArgsOrErr = parseArgs(Argc, Argv);
  if (auto EC = ArgsOrErr.getError()) {
    llvm::errs() << EC.message() << "\n";
    return false;
  }
  std::unique_ptr<llvm::opt::InputArgList> Args = std::move(ArgsOrErr.get());

  // Handle /help
  if (Args->hasArg(OPT_help)) {
    printHelp(Argv[0]);
    return true;
  }

  if (Args->filtered_begin(OPT_INPUT) == Args->filtered_end()) {
    llvm::errs() << "no input files.\n";
    return false;
  }

  // Handle /verbose
  if (Args->hasArg(OPT_verbose))
    Config->Verbose = true;

  // Handle /entry
  if (auto *Arg = Args->getLastArg(OPT_entry))
    Config->EntryName = Arg->getValue();

  // Handle /machine
  auto MTOrErr = getMachineType(Args.get());
  if (auto EC = MTOrErr.getError()) {
    llvm::errs() << EC.message() << "\n";
    return false;
  }
  Config->MachineType = MTOrErr.get();

  // Handle /libpath
  for (auto *Arg : Args->filtered(OPT_libpath)) {
    // Inserting at front of a vector is okay because it's short.
    // +1 because the first entry is always "." (current directory).
    SearchPaths.insert(SearchPaths.begin() + 1, Arg->getValue());
  }

  // Handle /nodefaultlib:<filename>
  for (auto *Arg : Args->filtered(OPT_nodefaultlib))
    Config->NoDefaultLibs.insert(doFindLib(Arg->getValue()));

  // Handle /nodefaultlib
  if (Args->hasArg(OPT_nodefaultlib_all))
    Config->NoDefaultLibAll = true;

  // Handle /base
  if (auto *Arg = Args->getLastArg(OPT_base)) {
    if (auto EC = parseNumbers(Arg->getValue(), &Config->ImageBase)) {
      llvm::errs() << "/base: " << EC.message() << "\n";
      return false;
    }
  }

  // Handle /stack
  if (auto *Arg = Args->getLastArg(OPT_stack)) {
    if (auto EC = parseNumbers(Arg->getValue(), &Config->StackReserve,
                               &Config->StackCommit)) {
      llvm::errs() << "/stack: " << EC.message() << "\n";
      return false;
    }
  }

  // Handle /heap
  if (auto *Arg = Args->getLastArg(OPT_heap)) {
    if (auto EC = parseNumbers(Arg->getValue(), &Config->HeapReserve,
                               &Config->HeapCommit)) {
      llvm::errs() << "/heap: " << EC.message() << "\n";
      return false;
    }
  }

  // Handle /version
  if (auto *Arg = Args->getLastArg(OPT_version)) {
    if (auto EC = parseVersion(Arg->getValue(), &Config->MajorImageVersion,
                               &Config->MinorImageVersion)) {
      llvm::errs() << "/version: " << EC.message() << "\n";
      return false;
    }
  }

  // Handle /subsystem
  if (auto *Arg = Args->getLastArg(OPT_subsystem)) {
    if (auto EC = parseSubsystem(Arg->getValue(), &Config->Subsystem,
                                 &Config->MajorOSVersion,
                                 &Config->MinorOSVersion)) {
      llvm::errs() << "/subsystem: " << EC.message() << "\n";
      return false;
    }
  }

  // Create a list of input files. Files can be given as arguments
  // for /defaultlib option.
  std::vector<StringRef> Inputs;
  for (auto *Arg : Args->filtered(OPT_INPUT))
    if (Optional<StringRef> Path = findFile(Arg->getValue()))
      Inputs.push_back(*Path);
  for (auto *Arg : Args->filtered(OPT_defaultlib))
    if (Optional<StringRef> Path = findLib(Arg->getValue()))
      Inputs.push_back(*Path);

  // Create a symbol table.
  SymbolTable Symtab;

  // Add undefined symbols given via the command line.
  // (/include is equivalent to Unix linker's -u option.)
  for (auto *Arg : Args->filtered(OPT_incl)) {
    StringRef Sym = Arg->getValue();
    Symtab.addUndefined(Sym);
    Config->GCRoots.insert(Sym);
  }

  // Parse all input files and put all symbols to the symbol table.
  // The symbol table will take care of name resolution.
  for (StringRef Path : Inputs) {
    auto FileOrErr = openFile(Path);
    if (auto EC = FileOrErr.getError()) {
      llvm::errs() << Path << ": " << EC.message() << "\n";
      return false;
    }
    std::unique_ptr<InputFile> File = std::move(FileOrErr.get());
    if (auto EC = Symtab.addFile(std::move(File))) {
      llvm::errs() << Path << ": " << EC.message() << "\n";
      return false;
    }
  }

  // Add weak aliases. Weak aliases is a mechanism to give remaining
  // undefined symbols final chance to be resolved successfully.
  // This is symbol renaming.
  for (auto *Arg : Args->filtered(OPT_alternatename)) {
    // Parse a string of the form of "/alternatename:From=To".
    StringRef From, To;
    std::tie(From, To) = StringRef(Arg->getValue()).split('=');
    if (From.empty() || To.empty()) {
      llvm::errs() << "/alternatename: invalid argument: "
                   << Arg->getValue() << "\n";
      return false;
    }
    // If From is already resolved to a Defined type, do nothing.
    // Otherwise, rename it to see if To can be resolved instead.
    if (Symtab.find(From))
      continue;
    if (auto EC = Symtab.rename(From, To)) {
      llvm::errs() << EC.message() << "\n";
      return false;
    }
  }

  // Windows specific -- If entry point name is not given, we need to
  // infer that from user-defined entry name. The symbol table takes
  // care of details.
  if (Config->EntryName.empty()) {
    auto EntryOrErr = Symtab.findDefaultEntry();
    if (auto EC = EntryOrErr.getError()) {
      llvm::errs() << EC.message() << "\n";
      return false;
    }
    Config->EntryName = EntryOrErr.get();
  }
  Config->GCRoots.insert(Config->EntryName);

  // Make sure we have resolved all symbols.
  if (Symtab.reportRemainingUndefines())
    return false;

  // Do LTO by compiling bitcode input files to a native COFF file
  // then link that file.
  if (auto EC = Symtab.addCombinedLTOObject()) {
    llvm::errs() << EC.message() << "\n";
    return false;
  }

  // /include option takes precedence over garbage collection.
  for (auto *Arg : Args->filtered(OPT_incl))
    Symtab.find(Arg->getValue())->markLive();

  // Windows specific -- if no /subsystem is given, we need to infer
  // that from entry point name.
  if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
    Config->Subsystem =
      StringSwitch<WindowsSubsystem>(Config->EntryName)
          .Case("mainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_CUI)
          .Case("wmainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_CUI)
          .Case("WinMainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_GUI)
          .Case("wWinMainCRTStartup", IMAGE_SUBSYSTEM_WINDOWS_GUI)
          .Default(IMAGE_SUBSYSTEM_UNKNOWN);
    if (Config->Subsystem == IMAGE_SUBSYSTEM_UNKNOWN) {
      llvm::errs() << "subsystem must be defined\n";
      return false;
    }
  }

  // Write the result.
  Writer Out(&Symtab);
  if (auto EC = Out.write(getOutputPath(Args.get()))) {
    llvm::errs() << EC.message() << "\n";
    return false;
  }
  return true;
}

} // namespace coff
} // namespace lld
<|endoftext|>