<commit_before>#include "lib/armv7m/crt0.h"
#include "lib/armv7m/exception_table.h"
#include "lib/armv7m/instructions.h"
#include "lib/armv7m/scb.h"

#include "runtime/ramcode.h"

#include "vga/graphics_1.h"
#include "vga/timing.h"
#include "vga/vga.h"
#include "vga/rast/bitmap_1.h"
#include "vga/rast/text_10x16.h"

using vga::rast::Bitmap_1;

typedef vga::Rasterizer::Pixel Pixel;

/*******************************************************************************
 * Screen partitioning
 */

static constexpr unsigned text_cols = 800;
static constexpr unsigned text_rows = 16 * 16;

static constexpr unsigned gfx_cols = 800;
static constexpr unsigned gfx_rows = 600 - text_rows;

/*******************************************************************************
 * The Graphics Parts
 */

static Bitmap_1 gfx_rast(gfx_cols, gfx_rows);

static void set_ball(vga::Graphics1 &g, unsigned x, unsigned y) {
  g.set_pixel(x, y);
  g.set_pixel(x - 1, y);
  g.set_pixel(x + 1, y);
  g.set_pixel(x, y - 1);
  g.set_pixel(x, y + 1);
}

static void clear_ball(vga::Graphics1 &g, unsigned x, unsigned y) {
  g.clear_pixel(x, y);
  g.clear_pixel(x - 1, y);
  g.clear_pixel(x + 1, y);
  g.clear_pixel(x, y - 1);
  g.clear_pixel(x, y + 1);
}

static void step_ball(int &x, int &y,
                      int other_x, int other_y,
                      int &xi, int &yi) {
  vga::Graphics1 g = gfx_rast.make_bg_graphics();

  clear_ball(g, x, y);
  x = other_x + xi;
  y = other_y + yi;

  if (x < 0) {
    x = 0;
    xi = -xi;
  }

  if (y < 0) {
    y = 0;
    yi = -yi;
  }

  if (x >= static_cast<int>(gfx_cols)) {
    x = gfx_cols - 1;
    xi = -xi;
  }

  if (y >= static_cast<int>(gfx_rows)) {
    y = gfx_rows - 1;
    yi = -yi;
  }

  set_ball(g, x, y);

  ++yi;
}

/*******************************************************************************
 * The Text Parts
 */

static vga::rast::Text_10x16 text_rast(text_cols, text_rows, gfx_rows);

static constexpr unsigned t_right_margin = (text_cols + 9) / 10;
static constexpr unsigned t_bottom_margin = (text_rows + 15) / 16;

static unsigned t_row = 0, t_col = 0;

static void type_raw(Pixel fore, Pixel back, char c) {
  text_rast.put_char(t_col, t_row, fore, back, c);
  ++t_col;
  if (t_col == t_right_margin) {
    t_col = 0;
    ++t_row;
    if (t_row == t_bottom_margin) t_row = 0;
  }
}

static void type(Pixel fore, Pixel back, char c) {
  switch (c) {
    case '\n':
      do {
        type_raw(fore, back, ' ');
      } while (t_col);
      return;

    default:
      type_raw(fore, back, c);
      return;
  }
}

static void type(Pixel fore, Pixel back, char const *s) {
  while (char c = *s++) {
    type(fore, back, c);
  }
}

static void rainbow_type(char const *s) {
  unsigned x = 0;
  while (char c = *s++) {
    type(x & 0b111111, ~x & 0b111111, c);
    ++x;
  }
}

static void cursor_to(unsigned col, unsigned row) {
  if (col >= t_right_margin) col = t_right_margin - 1;
  if (row >= t_bottom_margin) row = t_bottom_margin - 1;

  t_col = col;
  t_row = row;
}

static void text_at(unsigned col, unsigned row,
                    Pixel fore, Pixel back,
                    char const *s) {
  cursor_to(col, row);
  type(fore, back, s);
}

static void text_centered(unsigned row, Pixel fore, Pixel back, char const *s) {
  unsigned len = 0;
  while (s[len]) ++len;

  unsigned left_margin = 40 - len / 2;
  unsigned right_margin = t_right_margin - len - left_margin;

  cursor_to(0, row);
  for (unsigned i = 0; i < left_margin; ++i) type(fore, back, ' ');
  type(fore, back, s);
  for (unsigned i = 0; i < right_margin; ++i) type(fore, back, ' ');
}

enum {
  white   = 0b111111,
  lt_gray = 0b101010,
  dk_gray = 0b010101,
  black   = 0b000000,

  red     = 0b000011,
  green   = 0b001100,
  blue    = 0b110000,
};

/*******************************************************************************
 * The Startup Routine
 */

void v7m_reset_handler() {
  armv7m::crt0_init();
  runtime::ramcode_init();

  // Enable fault reporting.
  armv7m::scb.write_shcsr(armv7m::scb.read_shcsr()
                          .with_memfaultena(true)
                          .with_busfaultena(true)
                          .with_usgfaultena(true));

  // Enable floating point automatic/lazy state preservation.
  // The CONTROL bit governing FP will be set automatically when first used.
  armv7m::scb_fp.write_fpccr(armv7m::scb_fp.read_fpccr()
                             .with_aspen(true)
                             .with_lspen(true));
  armv7m::instruction_synchronization_barrier();  // Now please.

  // Enable access to the floating point coprocessor.
  armv7m::scb.write_cpacr(armv7m::scb.read_cpacr()
                          .with_cp11(armv7m::Scb::CpAccess::full)
                          .with_cp10(armv7m::Scb::CpAccess::full));

  // It is now safe to use floating point.

  vga::init();

  gfx_rast.activate(vga::timing_vesa_800x600_60hz);
  gfx_rast.set_fg_color(0b111111);
  gfx_rast.set_bg_color(0b100000);

  text_rast.activate(vga::timing_vesa_800x600_60hz);
  text_rast.clear_framebuffer(0);

  text_centered(0, white, dk_gray, "800x600 Mixed Graphics Modes Demo");
  cursor_to(0, 2);
  type(white, black, "Bitmap framebuffer combined with ");
  type(black, white, "attributed");
  type(red, black, " 256");
  type(green, black, " color ");
  type(blue, black, "text.");
  cursor_to(0, 4);
  rainbow_type("The quick brown fox jumped over the lazy dog. "
               "0123456789!@#$%^{}");

  text_at(0, 6, white, 0b100000,
      "     Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ut\n"
      "     tellus quam. Cras ornare facilisis sollicitudin. Quisque quis\n"
      "     imperdiet mauris. Proin malesuada nibh dolor, eu luctus mauris\n"
      "     ultricies vitae. Interdum et malesuada fames ac ante ipsum primis\n"
      "     in faucibus. Aenean tincidunt viverra ultricies. Quisque rutrum\n"
      "     vehicula pulvinar.\n");

  text_at(0, 15, white, black, "60 fps / 40MHz pixel clock");
  text_at(58, 36, white, black, "Frame number:");

  vga::configure_band(0, gfx_rows, &gfx_rast);
  vga::configure_band(gfx_rows, text_rows, &text_rast);
  vga::configure_timing(vga::timing_vesa_800x600_60hz);

  unsigned const num_balls = 60;
  int x[num_balls][2], y[num_balls][2];
  int xi[num_balls], yi[num_balls];

  unsigned seed = 1118;
  for (unsigned n = 0; n < num_balls; ++n) {
    seed = (seed * 1664525) + 1013904223;
    x[n][0] = x[n][1] = seed % gfx_cols;
    seed = (seed * 1664525) + 1013904223;
    y[n][0] = y[n][1] = seed % (gfx_rows*2/3);

    seed = (seed * 1664525) + 1013904223;
    xi[n] = seed % 9 - 5;
    seed = (seed * 1664525) + 1013904223;
    yi[n] = seed % 3 - 2;
  }

  char fc[9];
  fc[8] = 0;
  unsigned frame = 0;

  while (1) {
    unsigned f = ++frame;

    for (unsigned i = 8; i > 0; --i) {
      unsigned n = f & 0xF;
      fc[i - 1] = n > 9 ? 'A' + n - 10 : '0' + n;
      f >>= 4;
    }
    text_at(72, 15, red, black, fc);
    for (unsigned n = 0; n < num_balls; ++n) {
      step_ball(x[n][0], y[n][0], x[n][1], y[n][1], xi[n], yi[n]);
    }
    gfx_rast.flip();

    f = ++frame;
    for (unsigned i = 8; i > 0; --i) {
      unsigned n = f & 0xF;
      fc[i - 1] = n > 9 ? 'A' + n - 10 : '0' + n;
      f >>= 4;
    }
    text_at(72, 15, red, black, fc);
    for (unsigned n = 0; n < num_balls; ++n) {
      step_ball(x[n][1], y[n][1], x[n][0], y[n][0], xi[n], yi[n]);
    }
    gfx_rast.flip();
  }
}
<commit_msg>demo/hires_mix: rejigger particle simulation.<commit_after>#include "lib/armv7m/crt0.h"
#include "lib/armv7m/exception_table.h"
#include "lib/armv7m/instructions.h"
#include "lib/armv7m/scb.h"

#include "runtime/ramcode.h"

#include "vga/graphics_1.h"
#include "vga/timing.h"
#include "vga/vga.h"
#include "vga/rast/bitmap_1.h"
#include "vga/rast/text_10x16.h"

using vga::rast::Bitmap_1;

typedef vga::Rasterizer::Pixel Pixel;

/*******************************************************************************
 * Screen partitioning
 */

static constexpr unsigned text_cols = 800;
static constexpr unsigned text_rows = 16 * 16;

static constexpr unsigned gfx_cols = 800;
static constexpr unsigned gfx_rows = 600 - text_rows;

/*******************************************************************************
 * The Graphics Parts
 */

static Bitmap_1 gfx_rast(gfx_cols, gfx_rows);

class Particle {
public:
  static constexpr unsigned lifetime = 120;
  static unsigned seed;

  void randomize() {
    _x[0] = _x[1] = rand() % gfx_cols;
    _y[0] = _y[1] = rand() % (gfx_rows * 2/3);
    _dx = rand() % 9 - 5;
    _dy = rand() % 3 - 2;
  }

  void nudge(int ddx, int ddy) {
    _dx += ddx;
    _dy += ddy;
  }

  void step(vga::Graphics1 &g) {
    g.clear_pixel(_x[1], _y[1]);
    g.clear_pixel(_x[1] - 1, _y[1]);
    g.clear_pixel(_x[1] + 1, _y[1]);
    g.clear_pixel(_x[1], _y[1] - 1);
    g.clear_pixel(_x[1], _y[1] + 1);

    _x[1] = _x[0];
    _y[1] = _y[0];

    int x_ = _x[0] + _dx;
    int y_ = _y[0] + _dy;

    if (x_ < 0) {
      x_ = 0;
      _dx = -_dx;
    }

    if (y_ < 0) {
      y_ = 0;
      _dy = -_dy;
    }

    if (x_ >= static_cast<int>(gfx_cols)) {
      x_ = gfx_cols - 1;
      _dx = -_dx;
    }

    if (y_ >= static_cast<int>(gfx_rows)) {
      y_ = gfx_rows - 1;
      _dy = -_dy;
    }

    _x[0] = x_;
    _y[0] = y_;

    g.set_pixel(_x[0], _y[0]);
    g.set_pixel(_x[0] - 1, _y[0]);
    g.set_pixel(_x[0] + 1, _y[0]);
    g.set_pixel(_x[0], _y[0] - 1);
    g.set_pixel(_x[0], _y[0] + 1);
  }

private:
  int _x[2], _y[2];
  int _dx, _dy;

  unsigned rand() {
    seed = (seed * 1664525) + 1013904223;
    return seed;
  }
};

unsigned Particle::seed = 1118;

static constexpr unsigned particle_count = 500;

static Particle particles[particle_count];

static void update_particles() {
  vga::Graphics1 g = gfx_rast.make_bg_graphics();
  for (Particle &p : particles) {
    p.step(g);
    p.nudge(0, 1);
  }
  gfx_rast.flip();
}

/*******************************************************************************
 * The Text Parts
 */

static vga::rast::Text_10x16 text_rast(text_cols, text_rows, gfx_rows);

static constexpr unsigned t_right_margin = (text_cols + 9) / 10;
static constexpr unsigned t_bottom_margin = (text_rows + 15) / 16;

static unsigned t_row = 0, t_col = 0;

static void type_raw(Pixel fore, Pixel back, char c) {
  text_rast.put_char(t_col, t_row, fore, back, c);
  ++t_col;
  if (t_col == t_right_margin) {
    t_col = 0;
    ++t_row;
    if (t_row == t_bottom_margin) t_row = 0;
  }
}

static void type(Pixel fore, Pixel back, char c) {
  switch (c) {
    case '\n':
      do {
        type_raw(fore, back, ' ');
      } while (t_col);
      return;

    default:
      type_raw(fore, back, c);
      return;
  }
}

static void type(Pixel fore, Pixel back, char const *s) {
  while (char c = *s++) {
    type(fore, back, c);
  }
}

static void rainbow_type(char const *s) {
  unsigned x = 0;
  while (char c = *s++) {
    type(x & 0b111111, ~x & 0b111111, c);
    ++x;
  }
}

static void cursor_to(unsigned col, unsigned row) {
  if (col >= t_right_margin) col = t_right_margin - 1;
  if (row >= t_bottom_margin) row = t_bottom_margin - 1;

  t_col = col;
  t_row = row;
}

static void text_at(unsigned col, unsigned row,
                    Pixel fore, Pixel back,
                    char const *s) {
  cursor_to(col, row);
  type(fore, back, s);
}

static void text_centered(unsigned row, Pixel fore, Pixel back, char const *s) {
  unsigned len = 0;
  while (s[len]) ++len;

  unsigned left_margin = 40 - len / 2;
  unsigned right_margin = t_right_margin - len - left_margin;

  cursor_to(0, row);
  for (unsigned i = 0; i < left_margin; ++i) type(fore, back, ' ');
  type(fore, back, s);
  for (unsigned i = 0; i < right_margin; ++i) type(fore, back, ' ');
}

enum {
  white   = 0b111111,
  lt_gray = 0b101010,
  dk_gray = 0b010101,
  black   = 0b000000,

  red     = 0b000011,
  green   = 0b001100,
  blue    = 0b110000,
};

/*******************************************************************************
 * The Startup Routine
 */

void v7m_reset_handler() {
  armv7m::crt0_init();
  runtime::ramcode_init();

  // Enable fault reporting.
  armv7m::scb.write_shcsr(armv7m::scb.read_shcsr()
                          .with_memfaultena(true)
                          .with_busfaultena(true)
                          .with_usgfaultena(true));

  // Enable floating point automatic/lazy state preservation.
  // The CONTROL bit governing FP will be set automatically when first used.
  armv7m::scb_fp.write_fpccr(armv7m::scb_fp.read_fpccr()
                             .with_aspen(true)
                             .with_lspen(true));
  armv7m::instruction_synchronization_barrier();  // Now please.

  // Enable access to the floating point coprocessor.
  armv7m::scb.write_cpacr(armv7m::scb.read_cpacr()
                          .with_cp11(armv7m::Scb::CpAccess::full)
                          .with_cp10(armv7m::Scb::CpAccess::full));

  // It is now safe to use floating point.

  vga::init();

  gfx_rast.activate(vga::timing_vesa_800x600_60hz);
  gfx_rast.set_fg_color(0b111111);
  gfx_rast.set_bg_color(0b100000);

  text_rast.activate(vga::timing_vesa_800x600_60hz);
  text_rast.clear_framebuffer(0);

  text_centered(0, white, dk_gray, "800x600 Mixed Graphics Modes Demo");
  cursor_to(0, 2);
  type(white, black, "Bitmap framebuffer combined with ");
  type(black, white, "attributed");
  type(red, black, " 256");
  type(green, black, " color ");
  type(blue, black, "text.");
  cursor_to(0, 4);
  rainbow_type("The quick brown fox jumped over the lazy dog. "
               "0123456789!@#$%^{}");

  text_at(0, 6, white, 0b100000,
      "     Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam ut\n"
      "     tellus quam. Cras ornare facilisis sollicitudin. Quisque quis\n"
      "     imperdiet mauris. Proin malesuada nibh dolor, eu luctus mauris\n"
      "     ultricies vitae. Interdum et malesuada fames ac ante ipsum primis\n"
      "     in faucibus. Aenean tincidunt viverra ultricies. Quisque rutrum\n"
      "     vehicula pulvinar.\n");

  text_at(0, 15, white, black, "60 fps / 40MHz pixel clock");
  text_at(58, 36, white, black, "Frame number:");

  vga::configure_band(0, gfx_rows, &gfx_rast);
  vga::configure_band(gfx_rows, text_rows, &text_rast);
  vga::configure_timing(vga::timing_vesa_800x600_60hz);

  for (Particle &p : particles) p.randomize();

  char fc[9];
  fc[8] = 0;
  unsigned frame = 0;

  while (1) {
    unsigned f = ++frame;

    for (unsigned i = 8; i > 0; --i) {
      unsigned n = f & 0xF;
      fc[i - 1] = n > 9 ? 'A' + n - 10 : '0' + n;
      f >>= 4;
    }
    text_at(72, 15, red, black, fc);
    update_particles();

    f = ++frame;
    for (unsigned i = 8; i > 0; --i) {
      unsigned n = f & 0xF;
      fc[i - 1] = n > 9 ? 'A' + n - 10 : '0' + n;
      f >>= 4;
    }
    text_at(72, 15, red, black, fc);
    update_particles();
  }
}
<|endoftext|>


<commit_before>#include <assert.h>
#include <cstdio>

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/IRReader/IRReader.h>

#include <iostream>
#include <string>

#include "../src/LLVMDependenceGraph.h"

using namespace dg;
using llvm::errs;

static void dump_to_dot(LLVMDGNode *n, std::ostream& out)
{
    const llvm::Value *val;

    /* do not draw multiple edges */
    if (n->getDFSrun() == 1)
        return;
    else
        n->setDFSrun(1);

    for (auto I = n->control_begin(), E = n->control_end();
         I != E; ++I)
        out << "\tNODE" << n << " -> NODE" <<  *I << "\n";
    for (auto I = n->dependence_begin(), E = n->dependence_end();
         I != E; ++I)
        out << "\tNODE" << n << " -> NODE" <<  *I << " [color=red]\n";
#if ENABLE_CFG
    for (auto I = n->succ_begin(), E = n->succ_end();
         I != E; ++I)
        out << "\tNODE" << n << " -> NODE" <<  *I << " [style=dotted]\n";
#endif /* ENABLE_CFG */

    if (n->getSubgraph()) {
        out << "\tNODE" << n << " -> NODE" <<  n->getSubgraph()->getEntry() << " [style=dashed]\n";
    }
}

static std::string& getValueName(const llvm::Value *val, std::string &str)
{
    llvm::raw_string_ostream s(str);

    str.clear();

    if (llvm::isa<llvm::Function>(val))
        s << "ENTRY " << val->getName();
    else
        s << *val;

    return s.str();
}

void print_to_dot(LLVMDependenceGraph *dg,
                  bool issubgraph = false,
                  const char *description = NULL)
{
    static unsigned subgraph_no = 0;
    const llvm::Value *val;
    std::string valName;
    std::ostream& out = std::cout;

    if (!dg)
        return;

    if (issubgraph) {
        out << "subgraph \"cluster_" << subgraph_no++;
    } else {
        out << "digraph \""<< description ? description : "DependencyGraph";
    }

    out << "\" {\n";

    for (auto I = dg->begin(), E = dg->end(); I != E; ++I)
    {
        auto n = I->second;
        if (!n) {
            if (!llvm::isa<llvm::Function>(val)) {
                getValueName(dg->getEntry()->getValue(), valName);
                errs() << "WARN [" << valName << "]: Node is NULL for value: " << *I->first << "\n";
            }

            continue;
        }

        val = n->getValue();

        print_to_dot(n->getSubgraph(), true);
        print_to_dot(n->getParameters(), true);

        getValueName(val, valName);

        out << "\tNODE" << n << " [label=\"" << valName;
        for (auto d : n->getDefs()) {
            getValueName(d->getValue(), valName);
            out << "\\nDEF " << valName;
        }
        for (auto d : n->getPtrs()) {
            getValueName(d->getValue(), valName);
            out << "\\nPTR " << valName;
        }

        out << "\"";
        if (n->isLoopHeader())
            out << "style=\"filled\" fillcolor=\"gray\"";
        out << "];\n";
            //<<" (runid=" << n->getDFSrun() << ")\"];\n";
    }

    for (auto I = dg->begin(), E = dg->end(); I != E; ++I) {
        auto n = I->second;
        if (!n) {
            if (!llvm::isa<llvm::Function>(val))
                errs() << "WARN [" << dg << "]: Node is NULL for value: " << *I->first << "\n";

            continue;
        }

        dump_to_dot(I->second, out);
    }

    out << "}\n";
}

int main(int argc, char *argv[])
{
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    std::unique_ptr<llvm::Module> M;
    const char *module, *ofile = NULL;

    if (argc == 3) {
        module = argv[1];
        ofile = argv[2];
        errs() << "Not supported yet\n";
        return 1;
    } else if (argc == 2) {
        module = argv[1];
    } else {
        errs() << "Usage: % IR_module [output_file]\n";
        return 1;
    }

    M = llvm::parseIRFile(module, SMD, context);
    if (!M) {
        SMD.print(argv[0], errs());
        return 1;
    }

    LLVMDependenceGraph d;
    d.build(&*M);

    print_to_dot(&d, false, "LLVM Dependence Graph");

    return 0;
}
<commit_msg>llvm-dg-dump: add edge from call-site to parameters<commit_after>#include <assert.h>
#include <cstdio>

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_ostream.h>
#include <llvm/IRReader/IRReader.h>

#include <iostream>
#include <string>

#include "../src/LLVMDependenceGraph.h"

using namespace dg;
using llvm::errs;

static void dump_to_dot(LLVMDGNode *n, std::ostream& out)
{
    const llvm::Value *val;

    /* do not draw multiple edges */
    if (n->getDFSrun() == 1)
        return;
    else
        n->setDFSrun(1);

    for (auto I = n->control_begin(), E = n->control_end();
         I != E; ++I)
        out << "\tNODE" << n << " -> NODE" <<  *I << "\n";
    for (auto I = n->dependence_begin(), E = n->dependence_end();
         I != E; ++I)
        out << "\tNODE" << n << " -> NODE" <<  *I << " [color=red]\n";
#if ENABLE_CFG
    for (auto I = n->succ_begin(), E = n->succ_end();
         I != E; ++I)
        out << "\tNODE" << n << " -> NODE" <<  *I << " [style=dotted]\n";
#endif /* ENABLE_CFG */

    if (n->getSubgraph()) {
        out << "\tNODE" << n << " -> NODE" <<  n->getSubgraph()->getEntry() << " [style=dashed]\n";
    }
}

static std::string& getValueName(const llvm::Value *val, std::string &str)
{
    llvm::raw_string_ostream s(str);

    str.clear();

    if (llvm::isa<llvm::Function>(val))
        s << "ENTRY " << val->getName();
    else
        s << *val;

    return s.str();
}

void print_to_dot(LLVMDependenceGraph *dg,
                  bool issubgraph = false,
                  const char *description = NULL)
{
    static unsigned subgraph_no = 0;
    const llvm::Value *val;
    std::string valName;
    std::ostream& out = std::cout;

    if (!dg)
        return;

    if (issubgraph) {
        out << "subgraph \"cluster_" << subgraph_no++;
    } else {
        out << "digraph \""<< description ? description : "DependencyGraph";
    }

    out << "\" {\n";

    for (auto I = dg->begin(), E = dg->end(); I != E; ++I)
    {
        auto n = I->second;
        if (!n) {
            if (!llvm::isa<llvm::Function>(val)) {
                getValueName(dg->getEntry()->getValue(), valName);
                errs() << "WARN [" << valName << "]: Node is NULL for value: " << *I->first << "\n";
            }

            continue;
        }

        val = n->getValue();

        print_to_dot(n->getSubgraph(), true);
        LLVMDependenceGraph *params = n->getParameters();
        if (params) {
            print_to_dot(params, true);

            // add control edge from call-site to the parameters subgraph
            out << "\tNODE" << n << " -> NODE" <<  params->getEntry() << "\n";
        }

        getValueName(val, valName);

        out << "\tNODE" << n << " [label=\"" << valName;
        for (auto d : n->getDefs()) {
            getValueName(d->getValue(), valName);
            out << "\\nDEF " << valName;
        }
        for (auto d : n->getPtrs()) {
            getValueName(d->getValue(), valName);
            out << "\\nPTR " << valName;
        }

        out << "\"";
        if (n->isLoopHeader())
            out << "style=\"filled\" fillcolor=\"gray\"";
        out << "];\n";
            //<<" (runid=" << n->getDFSrun() << ")\"];\n";
    }

    for (auto I = dg->begin(), E = dg->end(); I != E; ++I) {
        auto n = I->second;
        if (!n) {
            if (!llvm::isa<llvm::Function>(val))
                errs() << "WARN [" << dg << "]: Node is NULL for value: " << *I->first << "\n";

            continue;
        }

        dump_to_dot(I->second, out);
    }

    out << "}\n";
}

int main(int argc, char *argv[])
{
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    std::unique_ptr<llvm::Module> M;
    const char *module, *ofile = NULL;

    if (argc == 3) {
        module = argv[1];
        ofile = argv[2];
        errs() << "Not supported yet\n";
        return 1;
    } else if (argc == 2) {
        module = argv[1];
    } else {
        errs() << "Usage: % IR_module [output_file]\n";
        return 1;
    }

    M = llvm::parseIRFile(module, SMD, context);
    if (!M) {
        SMD.print(argv[0], errs());
        return 1;
    }

    LLVMDependenceGraph d;
    d.build(&*M);

    print_to_dot(&d, false, "LLVM Dependence Graph");

    return 0;
}
<|endoftext|>


<commit_before>#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <set>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <cstdlib>

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>

#if LLVM_VERSION_MAJOR >= 4
#include <llvm/Bitcode/BitcodeReader.h>
#else
#include <llvm/Bitcode/ReaderWriter.h>
#endif

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "llvm/analysis/PointsTo/PointsTo.h"
#include "analysis/PointsTo/PointsToFlowInsensitive.h"
#include "analysis/PointsTo/PointsToFlowSensitive.h"
#include "analysis/PointsTo/PointsToWithInvalidate.h"
#include "analysis/PointsTo/Pointer.h"

#include "TimeMeasure.h"

using namespace dg;
using namespace dg::analysis::pta;
using dg::debug::TimeMeasure;
using llvm::errs;

static bool verbose;
static bool ids_only = false;

std::unique_ptr<PointerAnalysis> PA;

enum PTType {
    FLOW_SENSITIVE = 1,
    FLOW_INSENSITIVE,
    WITH_INVALIDATE,
};

static std::string
getInstName(const llvm::Value *val)
{
    std::ostringstream ostr;
    llvm::raw_os_ostream ro(ostr);

    assert(val);
    if (llvm::isa<llvm::Function>(val))
        ro << val->getName().data();
    else
        ro << *val;

    ro.flush();

    // break the string if it is too long
    return ostr.str();
}

void printPSNodeType(enum PSNodeType type) {
    printf("%s", PSNodeTypeToCString(type));
}

static void dumpPointer(const Pointer& ptr, bool dot);

static void
printName(PSNode *node, bool dot)
{
    std::string nm;
    const char *name = nullptr;
    if (node->isNull()) {
        name = "null";
    } else if (node->isUnknownMemory()) {
        name = "unknown";
    } else if (node->isInvalidated() &&
        !node->getUserData<llvm::Value>()) {
            name = "invalidated";
    }

    if (!name) {
        if (ids_only) {
            printf(" <%u>", node->getID());
            return;
        }

        if (!node->getUserData<llvm::Value>()) {
            printf("<%u> (no name)\\n", node->getID());
            if (node->getType() == PSNodeType::CONSTANT) {
                dumpPointer(*(node->pointsTo.begin()), dot);
            } else if (node->getType() == PSNodeType::CALL_RETURN) {
                if (PSNode *paired = node->getPairedNode())
                    printName(paired, dot);
            } else if (PSNodeEntry *entry = PSNodeEntry::get(node)) {
                printf("%s\\n", entry->getFunctionName().c_str());
            }

            if (!dot)
                printf(" <%u>\n", node->getID());

            return;
        }

        nm = getInstName(node->getUserData<llvm::Value>());
        name = nm.c_str();
    }

    if (ids_only) {
        printf(" <%u>", node->getID());
        return;
    }

    // escape the " character
    for (int i = 0; name[i] != '\0'; ++i) {
        // crop long names
        if (i >= 70) {
            printf(" ...");
            break;
        }

        if (name[i] == '"')
            putchar('\\');

        putchar(name[i]);
    }
}

static void dumpPointer(const Pointer& ptr, bool dot)
{
    printName(ptr.target, dot);

    if (ptr.offset.isUnknown())
        puts(" + UNKNOWN");
    else
        printf(" + %lu", *ptr.offset);
}

static void
dumpMemoryObject(MemoryObject *mo, int ind, bool dot)
{
    for (auto& it : mo->pointsTo) {
        for (const Pointer& ptr : it.second) {
            // print indentation
            printf("%*s", ind, "");

            if (it.first.isUnknown())
                printf("[UNKNOWN] -> ");
            else
                printf("[%lu] -> ", *it.first);

            dumpPointer(ptr, dot);

            if (dot)
                printf("\\n");
            else
                putchar('\n');
        }
    }
}

static void
dumpMemoryMap(PointsToFlowSensitive::MemoryMapT *mm, int ind, bool dot)
{
    for (const auto& it : *mm) {
        // print the key
        if (!dot)
            printf("%*s", ind, "");

        putchar('[');
        printName(it.first, dot);

        if (dot)
            printf("\\n");
        else
            putchar('\n');

        dumpMemoryObject(it.second.get(), ind + 4, dot);
    }
}

static void
dumpPointerSubgraphData(PSNode *n, PTType type, bool dot = false)
{
    assert(n && "No node given");
    if (type == FLOW_INSENSITIVE) {
        MemoryObject *mo = n->getData<MemoryObject>();
        if (!mo)
            return;

        if (dot)
            printf("\\n    Memory: ---\\n");
        else
            printf("    Memory: ---\n");

        dumpMemoryObject(mo, 6, dot);

        if (!dot)
            printf("    -----------\n");
    } else {
        PointsToFlowSensitive::MemoryMapT *mm
            = n->getData<PointsToFlowSensitive::MemoryMapT>();
        if (!mm)
            return;

        if (dot)
            printf("\\n    Memory map: [%p]\\n", static_cast<void*>(mm));
        else
            printf("    Memory map: [%p]\n", static_cast<void*>(mm));

        dumpMemoryMap(mm, 6, dot);

        if (!dot)
            printf("    ----------------\n");
    }
}

static void
dumpPSNode(PSNode *n, PTType type)
{
    printf("NODE %3u: ", n->getID());
    printf("Ty: ");
    printPSNodeType(n->getType());
    printf("\\n");

    PSNodeAlloc *alloc = PSNodeAlloc::get(n);
    if (alloc &&
        (alloc->getSize() || alloc->isHeap() || alloc->isZeroInitialized()))
        printf(" [size: %lu, heap: %u, zeroed: %u]",
               alloc->getSize(), alloc->isHeap(), alloc->isZeroInitialized());

    if (n->pointsTo.empty()) {
        puts(" -- no points-to");
        return;
    } else
        putchar('\n');

    for (const Pointer& ptr : n->pointsTo) {
        printf("    -> ");
        printName(ptr.target, false);
        if (ptr.offset.isUnknown())
            puts(" + Offset::UNKNOWN");
        else
            printf(" + %lu\n", *ptr.offset);
    }
    if (verbose) {
        dumpPointerSubgraphData(n, type);
    }
}

static void
dumpPointerSubgraphdot(LLVMPointerAnalysis *pta, PTType type)
{

    printf("digraph \"Pointer State Subgraph\" {\n");

    /* dump nodes */
    const auto& nodes = pta->getNodes();
    for (PSNode *node : nodes) {
        if (!node)
            continue;
        printf("\tNODE%u [label=\"<%u> ", node->getID(), node->getID());
        printPSNodeType(node->getType());
        printf("\\n");
        printName(node, true);
        printf("\\nparent: %u\\n", node->getParent() ? node->getParent()->getID() : 0);

        PSNodeAlloc *alloc = PSNodeAlloc::get(node);
        if (alloc && (alloc->getSize() || alloc->isHeap() || alloc->isZeroInitialized()))
            printf("\\n[size: %lu, heap: %u, zeroed: %u]",
               alloc->getSize(), alloc->isHeap(), alloc->isZeroInitialized());

        if (verbose && node->getOperandsNum() > 0) {
            printf("\\n--- operands ---\\n");
            for (PSNode *op : node->getOperands()) {
                printName(op, true);
                printf("\\n");
            }
            printf("------\\n");
        }

        for (const Pointer& ptr : node->pointsTo) {
            printf("\\n    -> ");
            printName(ptr.target, true);
            printf(" + ");
            if (ptr.offset.isUnknown())
                printf("Offset::UNKNOWN");
            else
                printf("%lu", *ptr.offset);
        }

        if (verbose)
            dumpPointerSubgraphData(node, type, true /* dot */);

        printf("\", shape=box");
        if (node->getType() != PSNodeType::STORE) {
            if (node->pointsTo.size() == 0
                && (node->getType() == PSNodeType::LOAD ||
                    node->getType() == PSNodeType::GEP  ||
                    node->getType() == PSNodeType::CAST ||
                    node->getType() == PSNodeType::PHI))
                printf(", style=filled, fillcolor=red");
        } else {
            printf(", style=filled, fillcolor=orange");
        }

        printf("]\n");
    }

    /* dump edges */
    for (PSNode *node : nodes) {
        if (!node) // node id 0 is nullptr
            continue;

        for (PSNode *succ : node->getSuccessors()) {
            printf("\tNODE%u -> NODE%u [penwidth=2]\n",
                   node->getID(), succ->getID());
        }

        for (PSNode *op : node->getOperands()) {
            printf("\tNODE%u -> NODE%u [color=blue,style=dotted,constraint=false]\n",
                   op->getID(), node->getID());
        }
    }

    printf("}\n");
}

static void
dumpPointerSubgraph(LLVMPointerAnalysis *pta, PTType type, bool todot)
{
    assert(pta);

    if (todot)
        dumpPointerSubgraphdot(pta, type);
    else {
        const auto& nodes = pta->getNodes();
        for (PSNode *node : nodes) {
            if (node) // node id 0 is nullptr
                dumpPSNode(node, type);
        }
    }
}

int main(int argc, char *argv[])
{
    llvm::Module *M;
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    bool todot = false;
    const char *module = nullptr;
    PTType type = FLOW_INSENSITIVE;
    uint64_t field_senitivity = Offset::UNKNOWN;

    // parse options
    for (int i = 1; i < argc; ++i) {
        // run given points-to analysis
        if (strcmp(argv[i], "-pta") == 0) {
            if (strcmp(argv[i+1], "fs") == 0)
                type = FLOW_SENSITIVE;
            else if (strcmp(argv[i+1], "inv") == 0)
                type = WITH_INVALIDATE;
        } else if (strcmp(argv[i], "-pta-field-sensitive") == 0) {
            field_senitivity = static_cast<uint64_t>(atoll(argv[i + 1]));
        } else if (strcmp(argv[i], "-dot") == 0) {
            todot = true;
        } else if (strcmp(argv[i], "-ids-only") == 0) {
            ids_only = true;
        } else if (strcmp(argv[i], "-v") == 0) {
            verbose = true;
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % IR_module [output_file]\n";
        return 1;
    }

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 5))
    M = llvm::ParseIRFile(module, SMD, context);
#else
    auto _M = llvm::parseIRFile(module, SMD, context);
    // _M is unique pointer, we need to get Module *
    M = _M.get();
#endif

    if (!M) {
        llvm::errs() << "Failed parsing '" << module << "' file:\n";
        SMD.print(argv[0], errs());
        return 1;
    }

    TimeMeasure tm;

    LLVMPointerAnalysis PTA(M, field_senitivity);

    tm.start();

    // use createAnalysis instead of the run() method so that we won't delete
    // the analysis data (like memory objects) which may be needed
    if (type == FLOW_INSENSITIVE) {
        PA = std::unique_ptr<PointerAnalysis>(
            PTA.createPTA<analysis::pta::PointsToFlowInsensitive>()
            );
    } else if (type == WITH_INVALIDATE) {
        PA = std::unique_ptr<PointerAnalysis>(
            PTA.createPTA<analysis::pta::PointsToWithInvalidate>()
            );
    } else {
        PA = std::unique_ptr<PointerAnalysis>(
            PTA.createPTA<analysis::pta::PointsToFlowSensitive>()
            );
    }

    // run the analysis
    PA->run();

    tm.stop();
    tm.report("INFO: Points-to analysis [new] took");
    dumpPointerSubgraph(&PTA, type, todot);

    return 0;
}
<commit_msg>llvm-ps-dump: allow dumping the graph without running PTA<commit_after>#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

#include <set>
#include <string>
#include <iostream>
#include <sstream>
#include <fstream>
#include <cassert>
#include <cstdio>
#include <cstdlib>

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Instructions.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>

#if LLVM_VERSION_MAJOR >= 4
#include <llvm/Bitcode/BitcodeReader.h>
#else
#include <llvm/Bitcode/ReaderWriter.h>
#endif

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

#include "llvm/analysis/PointsTo/PointsTo.h"
#include "analysis/PointsTo/PointsToFlowInsensitive.h"
#include "analysis/PointsTo/PointsToFlowSensitive.h"
#include "analysis/PointsTo/PointsToWithInvalidate.h"
#include "analysis/PointsTo/Pointer.h"

#include "TimeMeasure.h"

using namespace dg;
using namespace dg::analysis::pta;
using dg::debug::TimeMeasure;
using llvm::errs;

static bool verbose;
static bool ids_only = false;
static bool dump_graph_only = false;

std::unique_ptr<PointerAnalysis> PA;

enum PTType {
    FLOW_SENSITIVE = 1,
    FLOW_INSENSITIVE,
    WITH_INVALIDATE,
};

static std::string
getInstName(const llvm::Value *val)
{
    std::ostringstream ostr;
    llvm::raw_os_ostream ro(ostr);

    assert(val);
    if (llvm::isa<llvm::Function>(val))
        ro << val->getName().data();
    else
        ro << *val;

    ro.flush();

    // break the string if it is too long
    return ostr.str();
}

void printPSNodeType(enum PSNodeType type) {
    printf("%s", PSNodeTypeToCString(type));
}

static void dumpPointer(const Pointer& ptr, bool dot);

static void
printName(PSNode *node, bool dot)
{
    std::string nm;
    const char *name = nullptr;
    if (node->isNull()) {
        name = "null";
    } else if (node->isUnknownMemory()) {
        name = "unknown";
    } else if (node->isInvalidated() &&
        !node->getUserData<llvm::Value>()) {
            name = "invalidated";
    }

    if (!name) {
        if (ids_only) {
            printf(" <%u>", node->getID());
            return;
        }

        if (!node->getUserData<llvm::Value>()) {
            printf("<%u> (no name)\\n", node->getID());
            if (node->getType() == PSNodeType::CONSTANT) {
                dumpPointer(*(node->pointsTo.begin()), dot);
            } else if (node->getType() == PSNodeType::CALL_RETURN) {
                if (PSNode *paired = node->getPairedNode())
                    printName(paired, dot);
            } else if (PSNodeEntry *entry = PSNodeEntry::get(node)) {
                printf("%s\\n", entry->getFunctionName().c_str());
            }

            if (!dot)
                printf(" <%u>\n", node->getID());

            return;
        }

        nm = getInstName(node->getUserData<llvm::Value>());
        name = nm.c_str();
    }

    if (ids_only) {
        printf(" <%u>", node->getID());
        return;
    }

    // escape the " character
    for (int i = 0; name[i] != '\0'; ++i) {
        // crop long names
        if (i >= 70) {
            printf(" ...");
            break;
        }

        if (name[i] == '"')
            putchar('\\');

        putchar(name[i]);
    }
}

static void dumpPointer(const Pointer& ptr, bool dot)
{
    printName(ptr.target, dot);

    if (ptr.offset.isUnknown())
        puts(" + UNKNOWN");
    else
        printf(" + %lu", *ptr.offset);
}

static void
dumpMemoryObject(MemoryObject *mo, int ind, bool dot)
{
    for (auto& it : mo->pointsTo) {
        for (const Pointer& ptr : it.second) {
            // print indentation
            printf("%*s", ind, "");

            if (it.first.isUnknown())
                printf("[UNKNOWN] -> ");
            else
                printf("[%lu] -> ", *it.first);

            dumpPointer(ptr, dot);

            if (dot)
                printf("\\n");
            else
                putchar('\n');
        }
    }
}

static void
dumpMemoryMap(PointsToFlowSensitive::MemoryMapT *mm, int ind, bool dot)
{
    for (const auto& it : *mm) {
        // print the key
        if (!dot)
            printf("%*s", ind, "");

        putchar('[');
        printName(it.first, dot);

        if (dot)
            printf("\\n");
        else
            putchar('\n');

        dumpMemoryObject(it.second.get(), ind + 4, dot);
    }
}

static void
dumpPointerSubgraphData(PSNode *n, PTType type, bool dot = false)
{
    assert(n && "No node given");
    if (type == FLOW_INSENSITIVE) {
        MemoryObject *mo = n->getData<MemoryObject>();
        if (!mo)
            return;

        if (dot)
            printf("\\n    Memory: ---\\n");
        else
            printf("    Memory: ---\n");

        dumpMemoryObject(mo, 6, dot);

        if (!dot)
            printf("    -----------\n");
    } else {
        PointsToFlowSensitive::MemoryMapT *mm
            = n->getData<PointsToFlowSensitive::MemoryMapT>();
        if (!mm)
            return;

        if (dot)
            printf("\\n    Memory map: [%p]\\n", static_cast<void*>(mm));
        else
            printf("    Memory map: [%p]\n", static_cast<void*>(mm));

        dumpMemoryMap(mm, 6, dot);

        if (!dot)
            printf("    ----------------\n");
    }
}

static void
dumpPSNode(PSNode *n, PTType type)
{
    printf("NODE %3u: ", n->getID());
    printf("Ty: ");
    printPSNodeType(n->getType());
    printf("\\n");

    PSNodeAlloc *alloc = PSNodeAlloc::get(n);
    if (alloc &&
        (alloc->getSize() || alloc->isHeap() || alloc->isZeroInitialized()))
        printf(" [size: %lu, heap: %u, zeroed: %u]",
               alloc->getSize(), alloc->isHeap(), alloc->isZeroInitialized());

    if (n->pointsTo.empty()) {
        puts(" -- no points-to");
        return;
    } else
        putchar('\n');

    for (const Pointer& ptr : n->pointsTo) {
        printf("    -> ");
        printName(ptr.target, false);
        if (ptr.offset.isUnknown())
            puts(" + Offset::UNKNOWN");
        else
            printf(" + %lu\n", *ptr.offset);
    }
    if (verbose) {
        dumpPointerSubgraphData(n, type);
    }
}

static void
dumpPointerSubgraphdot(LLVMPointerAnalysis *pta, PTType type)
{

    printf("digraph \"Pointer State Subgraph\" {\n");

    /* dump nodes */
    const auto& nodes = pta->getNodes();
    for (PSNode *node : nodes) {
        if (!node)
            continue;
        printf("\tNODE%u [label=\"<%u> ", node->getID(), node->getID());
        printPSNodeType(node->getType());
        printf("\\n");
        printName(node, true);
        printf("\\nparent: %u\\n", node->getParent() ? node->getParent()->getID() : 0);

        PSNodeAlloc *alloc = PSNodeAlloc::get(node);
        if (alloc && (alloc->getSize() || alloc->isHeap() || alloc->isZeroInitialized()))
            printf("\\n[size: %lu, heap: %u, zeroed: %u]",
               alloc->getSize(), alloc->isHeap(), alloc->isZeroInitialized());

        if (verbose && node->getOperandsNum() > 0) {
            printf("\\n--- operands ---\\n");
            for (PSNode *op : node->getOperands()) {
                printName(op, true);
                printf("\\n");
            }
            printf("------\\n");
        }

        for (const Pointer& ptr : node->pointsTo) {
            printf("\\n    -> ");
            printName(ptr.target, true);
            printf(" + ");
            if (ptr.offset.isUnknown())
                printf("Offset::UNKNOWN");
            else
                printf("%lu", *ptr.offset);
        }

        if (verbose)
            dumpPointerSubgraphData(node, type, true /* dot */);

        printf("\", shape=box");
        if (node->getType() != PSNodeType::STORE) {
            if (node->pointsTo.size() == 0
                && (node->getType() == PSNodeType::LOAD ||
                    node->getType() == PSNodeType::GEP  ||
                    node->getType() == PSNodeType::CAST ||
                    node->getType() == PSNodeType::PHI))
                printf(", style=filled, fillcolor=red");
        } else {
            printf(", style=filled, fillcolor=orange");
        }

        printf("]\n");
    }

    /* dump edges */
    for (PSNode *node : nodes) {
        if (!node) // node id 0 is nullptr
            continue;

        for (PSNode *succ : node->getSuccessors()) {
            printf("\tNODE%u -> NODE%u [penwidth=2]\n",
                   node->getID(), succ->getID());
        }

        for (PSNode *op : node->getOperands()) {
            printf("\tNODE%u -> NODE%u [color=blue,style=dotted,constraint=false]\n",
                   op->getID(), node->getID());
        }
    }

    printf("}\n");
}

static void
dumpPointerSubgraph(LLVMPointerAnalysis *pta, PTType type, bool todot)
{
    assert(pta);

    if (todot)
        dumpPointerSubgraphdot(pta, type);
    else {
        const auto& nodes = pta->getNodes();
        for (PSNode *node : nodes) {
            if (node) // node id 0 is nullptr
                dumpPSNode(node, type);
        }
    }
}

int main(int argc, char *argv[])
{
    llvm::Module *M;
    llvm::LLVMContext context;
    llvm::SMDiagnostic SMD;
    bool todot = false;
    const char *module = nullptr;
    PTType type = FLOW_INSENSITIVE;
    uint64_t field_senitivity = Offset::UNKNOWN;

    // parse options
    for (int i = 1; i < argc; ++i) {
        // run given points-to analysis
        if (strcmp(argv[i], "-pta") == 0) {
            if (strcmp(argv[i+1], "fs") == 0)
                type = FLOW_SENSITIVE;
            else if (strcmp(argv[i+1], "inv") == 0)
                type = WITH_INVALIDATE;
        } else if (strcmp(argv[i], "-pta-field-sensitive") == 0) {
            field_senitivity = static_cast<uint64_t>(atoll(argv[i + 1]));
        } else if (strcmp(argv[i], "-dot") == 0) {
            todot = true;
        } else if (strcmp(argv[i], "-ids-only") == 0) {
            ids_only = true;
        } else if (strcmp(argv[i], "-graph-only") == 0) {
            dump_graph_only = true;
        } else if (strcmp(argv[i], "-v") == 0) {
            verbose = true;
        } else {
            module = argv[i];
        }
    }

    if (!module) {
        errs() << "Usage: % IR_module [output_file]\n";
        return 1;
    }

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 5))
    M = llvm::ParseIRFile(module, SMD, context);
#else
    auto _M = llvm::parseIRFile(module, SMD, context);
    // _M is unique pointer, we need to get Module *
    M = _M.get();
#endif

    if (!M) {
        llvm::errs() << "Failed parsing '" << module << "' file:\n";
        SMD.print(argv[0], errs());
        return 1;
    }

    TimeMeasure tm;

    LLVMPointerAnalysis PTA(M, field_senitivity);

    tm.start();

    // use createAnalysis instead of the run() method so that we won't delete
    // the analysis data (like memory objects) which may be needed
    if (type == FLOW_INSENSITIVE) {
        PA = std::unique_ptr<PointerAnalysis>(
            PTA.createPTA<analysis::pta::PointsToFlowInsensitive>()
            );
    } else if (type == WITH_INVALIDATE) {
        PA = std::unique_ptr<PointerAnalysis>(
            PTA.createPTA<analysis::pta::PointsToWithInvalidate>()
            );
    } else {
        PA = std::unique_ptr<PointerAnalysis>(
            PTA.createPTA<analysis::pta::PointsToFlowSensitive>()
            );
    }

    if (dump_graph_only) {
        dumpPointerSubgraph(&PTA, type, true);
        return 0;
    }

    // run the analysis
    PA->run();

    tm.stop();
    tm.report("INFO: Points-to analysis [new] took");
    dumpPointerSubgraph(&PTA, type, todot);

    return 0;
}
<|endoftext|>


<commit_before>#include "graphics.h"
#include <SDL.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

#define error(fmt, ...) _error(__LINE__, fmt, __VA_ARGS__)
#define sdl_error(name, ...) _sdl_error(__LINE__, name)

static void _error(long  line, const char *fmt, ...);
static void _sdl_error(long  line, const char *name);
static void check_surface();
static void check_bpp();

static int const SURFACE_WIDTH  = 640;
static int const SURFACE_HEIGHT = 480;
static int const SURFACE_BPP    = 4;   //BytesPerPixel

static SDL_Surface *surface = NULL;
static uint32_t bgi_colors[16];

void initgraph(int *gdriver, int *gmode, const char *something) {
  if (surface) {
    error("initgraph() can only be called once", NULL);
  }

  if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
    sdl_error("SDL_Init");
  }

  if (SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL)) {
    sdl_error("SDL_EnableKeyRepeat");
  }

  if ((surface = SDL_SetVideoMode(
    SURFACE_WIDTH,
    SURFACE_HEIGHT,
    SURFACE_BPP * 8, //Bits Per Pixel
    SDL_HWSURFACE | SDL_DOUBLEBUF
  )) == NULL) {
    sdl_error("SDL_SetVideoMode");
  }

  bgi_colors[BLACK]        = SDL_MapRGB(surface->format, 0x00, 0x00, 0x00);
  bgi_colors[BLUE]         = SDL_MapRGB(surface->format, 0x00, 0x00, 0xFF);
  bgi_colors[GREEN]        = SDL_MapRGB(surface->format, 0x00, 0xFF, 0x00);
  bgi_colors[CYAN]         = SDL_MapRGB(surface->format, 0x00, 0xFF, 0xFF);
  bgi_colors[RED]          = SDL_MapRGB(surface->format, 0xFF, 0x00, 0x00);
  bgi_colors[MAGENTA]      = SDL_MapRGB(surface->format, 0xFF, 0x00, 0xFF);
  bgi_colors[BROWN]        = SDL_MapRGB(surface->format, 0xA5, 0x2A, 0x2A);
  bgi_colors[LIGHTGRAY]    = SDL_MapRGB(surface->format, 0xD3, 0xD3, 0xD3);
  bgi_colors[DARKGRAY]     = SDL_MapRGB(surface->format, 0xA9, 0xA9, 0xA9);
  bgi_colors[LIGHTBLUE]    = SDL_MapRGB(surface->format, 0xAD, 0xD8, 0xE6);
  bgi_colors[LIGHTGREEN]   = SDL_MapRGB(surface->format, 0x90, 0xEE, 0x90);
  bgi_colors[LIGHTCYAN]    = SDL_MapRGB(surface->format, 0xE0, 0xFF, 0xFF);
  bgi_colors[LIGHTRED]     = SDL_MapRGB(surface->format, 0xF0, 0x80, 0x80);
  bgi_colors[LIGHTMAGENTA] = SDL_MapRGB(surface->format, 0xDB, 0x70, 0x93);
  bgi_colors[YELLOW]       = SDL_MapRGB(surface->format, 0xFF, 0xFF, 0x00);
  bgi_colors[WHITE]        = SDL_MapRGB(surface->format, 0xFF, 0xFF, 0xFF);
}

void closegraph(void) {
  if (surface) {
    SDL_Quit();
    surface = NULL;
  }
}

int getpixel(int x, int y) {
  // TODO: Implement
  return 0;
}

void putpixel(int x, int y, int color) {
  uint8_t *pixel;

  check_surface();
  check_bpp();

  if (color < BLACK || color > WHITE) {
    error("Illegal color value in putpixel: %d", color);
  }

  if (SDL_LockSurface(surface) < 0) {
    sdl_error("SDL_LockSurface");
  }

  pixel = ((uint8_t *) surface->pixels) + y * surface->pitch + x * SURFACE_BPP;

  *(Uint32 *) pixel = bgi_colors[color];

  SDL_UnlockSurface(surface);

  SDL_Flip(surface);
}

int getcolor(void) {
  // TODO: Implement
  return 0;
}

void setcolor(int color) {
  // TODO: Implement
}

void getimage(int left, int top, int right, int bottom, void *pic) {
  // TODO: Implement
}

void putimage(int left, int top, void *pic, int mode) {
  // TODO: Implement
}

size_t imagesize(int left, int top, int right, int bottom) {
  // TODO: Implement
  return 0;
}

void line(int a_x, int a_y, int b_x, int b_y) {
  // TODO: Implement
}

void rectangle(int left, int top, int right, int bottom) {
  // TODO: Implement
}

void setfillstyle(int mode, int color) {
  // TODO: Implement
}

void floodfill(int x, int y, int color) {
  // TODO: Implement
}

void outtextxy(int x, int y, const char *text) {
  // TODO: Implement
}

int GetKeyState(int key) {
  // TODO: Implement
  return 0;
}

void SetNormalKeysMode(void) {
  // no implementation necessary
}

void SetButtonKeysMode(void) {
  // no implementation necessary
}

void delay(int milliseconds) {
  // TODO: Implement
}

void cleardevice(void) {
  // TODO: Implement
}

void itoa(int num, char *str, int base) {
  // Only writing impl for base 10 conversion
  if (base != 10) {
    fprintf(stderr, "iota() only supports base 10 conversion\n");
    exit(1);
  }

  // Stupid unsafe itoa has no buffer size parameter, so we have
  // to use sprintf instead of snprintf
  sprintf(str, "%d", num);
}

static void _error(long  line, const char *fmt, ...) {
  va_list args;

  va_start(args, fmt);
  fprintf(stderr, "graphics.cpp error on line %ld: ", line);
  vfprintf(stderr, fmt, args);
  fprintf(stderr, "\n");
  va_end(args);

  closegraph();

  exit(1);
}

static void _sdl_error(long  line, const char *name) {
  _error(line, "SDL function %s failed. Reason: %s", name, SDL_GetError());
}

static void check_surface() {
  if (surface == NULL) {
    error("surface is null", NULL);
  }
}

static void check_bpp() {
  if (surface->format->BytesPerPixel != SURFACE_BPP) {
    error("Expecting %d bytes per pxiel. Got %d",
          SURFACE_BPP,
          surface->format->BytesPerPixel);
  }
}
<commit_msg>Add implementation for getpixel<commit_after>#include "graphics.h"
#include <SDL.h>

#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif

#define error(fmt, ...) _error(__LINE__, fmt, __VA_ARGS__)
#define sdl_error(name, ...) _sdl_error(__LINE__, name)

static void _error(long  line, const char *fmt, ...);
static void _sdl_error(long  line, const char *name);
static void check_surface();
static void check_bpp();

static int const SURFACE_WIDTH  = 640;
static int const SURFACE_HEIGHT = 480;
static int const SURFACE_BPP    = 4;   //BytesPerPixel

static SDL_Surface *surface = NULL;
static uint32_t bgi_colors[16];

void initgraph(int *gdriver, int *gmode, const char *something) {
  if (surface) {
    error("initgraph() can only be called once", NULL);
  }

  if (SDL_Init(SDL_INIT_EVERYTHING) < 0) {
    sdl_error("SDL_Init");
  }

  if (SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL)) {
    sdl_error("SDL_EnableKeyRepeat");
  }

  if ((surface = SDL_SetVideoMode(
    SURFACE_WIDTH,
    SURFACE_HEIGHT,
    SURFACE_BPP * 8, //Bits Per Pixel
    SDL_HWSURFACE | SDL_DOUBLEBUF
  )) == NULL) {
    sdl_error("SDL_SetVideoMode");
  }

  bgi_colors[BLACK]        = SDL_MapRGB(surface->format, 0x00, 0x00, 0x00);
  bgi_colors[BLUE]         = SDL_MapRGB(surface->format, 0x00, 0x00, 0xFF);
  bgi_colors[GREEN]        = SDL_MapRGB(surface->format, 0x00, 0xFF, 0x00);
  bgi_colors[CYAN]         = SDL_MapRGB(surface->format, 0x00, 0xFF, 0xFF);
  bgi_colors[RED]          = SDL_MapRGB(surface->format, 0xFF, 0x00, 0x00);
  bgi_colors[MAGENTA]      = SDL_MapRGB(surface->format, 0xFF, 0x00, 0xFF);
  bgi_colors[BROWN]        = SDL_MapRGB(surface->format, 0xA5, 0x2A, 0x2A);
  bgi_colors[LIGHTGRAY]    = SDL_MapRGB(surface->format, 0xD3, 0xD3, 0xD3);
  bgi_colors[DARKGRAY]     = SDL_MapRGB(surface->format, 0xA9, 0xA9, 0xA9);
  bgi_colors[LIGHTBLUE]    = SDL_MapRGB(surface->format, 0xAD, 0xD8, 0xE6);
  bgi_colors[LIGHTGREEN]   = SDL_MapRGB(surface->format, 0x90, 0xEE, 0x90);
  bgi_colors[LIGHTCYAN]    = SDL_MapRGB(surface->format, 0xE0, 0xFF, 0xFF);
  bgi_colors[LIGHTRED]     = SDL_MapRGB(surface->format, 0xF0, 0x80, 0x80);
  bgi_colors[LIGHTMAGENTA] = SDL_MapRGB(surface->format, 0xDB, 0x70, 0x93);
  bgi_colors[YELLOW]       = SDL_MapRGB(surface->format, 0xFF, 0xFF, 0x00);
  bgi_colors[WHITE]        = SDL_MapRGB(surface->format, 0xFF, 0xFF, 0xFF);
}

void closegraph(void) {
  if (surface) {
    SDL_Quit();
    surface = NULL;
  }
}

int getpixel(int x, int y) {
  uint8_t *pixel;
  int color, pixel_value;

  check_surface();
  check_bpp();

  if (SDL_LockSurface(surface) < 0) {
    sdl_error("SDL_LockSurface");
  }

  pixel = ((uint8_t *) surface->pixels) + y * surface->pitch + x * SURFACE_BPP;

  SDL_UnlockSurface(surface);

  pixel_value = *(uint32_t *) pixel;

  for (color = BLACK; color <= WHITE; ++color) {
    if (pixel_value == bgi_colors[color])
      return color;
  }

  error("Unknown pixel value: %d", pixel_value);
}

void putpixel(int x, int y, int color) {
  uint8_t *pixel;

  check_surface();
  check_bpp();

  if (color < BLACK || color > WHITE) {
    error("Illegal color value in putpixel: %d", color);
  }

  if (SDL_LockSurface(surface) < 0) {
    sdl_error("SDL_LockSurface");
  }

  pixel = ((uint8_t *) surface->pixels) + y * surface->pitch + x * SURFACE_BPP;

  *(Uint32 *) pixel = bgi_colors[color];

  SDL_UnlockSurface(surface);

  SDL_Flip(surface);
}

int getcolor(void) {
  // TODO: Implement
  return 0;
}

void setcolor(int color) {
  // TODO: Implement
}

void getimage(int left, int top, int right, int bottom, void *pic) {
  // TODO: Implement
}

void putimage(int left, int top, void *pic, int mode) {
  // TODO: Implement
}

size_t imagesize(int left, int top, int right, int bottom) {
  // TODO: Implement
  return 0;
}

void line(int a_x, int a_y, int b_x, int b_y) {
  // TODO: Implement
}

void rectangle(int left, int top, int right, int bottom) {
  // TODO: Implement
}

void setfillstyle(int mode, int color) {
  // TODO: Implement
}

void floodfill(int x, int y, int color) {
  // TODO: Implement
}

void outtextxy(int x, int y, const char *text) {
  // TODO: Implement
}

int GetKeyState(int key) {
  // TODO: Implement
  return 0;
}

void SetNormalKeysMode(void) {
  // no implementation necessary
}

void SetButtonKeysMode(void) {
  // no implementation necessary
}

void delay(int milliseconds) {
  // TODO: Implement
}

void cleardevice(void) {
  // TODO: Implement
}

void itoa(int num, char *str, int base) {
  // Only writing impl for base 10 conversion
  if (base != 10) {
    fprintf(stderr, "iota() only supports base 10 conversion\n");
    exit(1);
  }

  // Stupid unsafe itoa has no buffer size parameter, so we have
  // to use sprintf instead of snprintf
  sprintf(str, "%d", num);
}

static void _error(long  line, const char *fmt, ...) {
  va_list args;

  va_start(args, fmt);
  fprintf(stderr, "graphics.cpp error on line %ld: ", line);
  vfprintf(stderr, fmt, args);
  fprintf(stderr, "\n");
  va_end(args);

  closegraph();

  exit(1);
}

static void _sdl_error(long  line, const char *name) {
  _error(line, "SDL function %s failed. Reason: %s", name, SDL_GetError());
}

static void check_surface() {
  if (surface == NULL) {
    error("surface is null", NULL);
  }
}

static void check_bpp() {
  if (surface->format->BytesPerPixel != SURFACE_BPP) {
    error("Expecting %d bytes per pxiel. Got %d",
          SURFACE_BPP,
          surface->format->BytesPerPixel);
  }
}
<|endoftext|>


<commit_before>#include "utils.h"
// <GL/glext.h> on Linux, <OpenGL/glext.h> on MacOS :(
#include "../glfw/deps/GL/glext.h"

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <sstream>
#include <fstream>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <defer.h>
#include <unistd.h>
#include <stb_image.h>

void flipTexture(unsigned char *textureData, int width, int height, int n) {
  for(int h = 0; h < height/2; ++h) {
    for(int w = 0; w < width; ++w) {
      for(int i = 0; i < n; ++i) {
        int offset1 = (h*width + w)*n + i;
        int offset2 = ((height - h - 1)*width + w)*n + i;
        unsigned char t = textureData[offset1];
        textureData[offset1] = textureData[offset2];
        textureData[offset2] = t;
      }
    }
  }
}

bool loadCommonTexture(char const* fname, GLuint textureId) {
  return loadCommonTextureExt(fname, textureId, false);
}

bool loadCommonTextureExt(char const* fname, GLuint textureId, bool flip) {
  int width, height, n;
  unsigned char *textureData = stbi_load(fname, &width, &height, &n, 0);
  if(textureData == nullptr) {
    std::cout << "ERROR: loadCommonTextureExt failed, fname = " << fname << ", stbi_load returned nullptr" << std::endl;
    return false;
  }
  defer(stbi_image_free(textureData));

  if(flip) flipTexture(textureData, width, height, n);

  glBindTexture(GL_TEXTURE_2D, textureId);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  // Generate mipmaps
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glGenerateMipmap(GL_TEXTURE_2D);

  // glBindTexture(GL_TEXTURE_2D, 0); // unbind
  return true;
}

#define DDS_HEADER_SIZE 128
#define DDS_SIGNATURE    0x20534444 // "DDS "
#define FORMAT_CODE_DXT1 0x31545844 // "DXT1"
#define FORMAT_CODE_DXT3 0x33545844 // "DXT3"
#define FORMAT_CODE_DXT5 0x35545844 // "DXT5"

bool loadDDSTexture(char const *fname, GLuint textureId) {
  int fd = open(fname, O_RDONLY, 0);
  if(fd < 0) {
    std::cout << "ERROR: loadDDSTexture - open failed, fname =  " << fname <<
      ", " << strerror(errno) << std::endl;
    return false;
  }
  defer(close(fd));

  struct stat st;
  if(fstat(fd, &st) < 0) {
    std::cout << "ERROR: loadDDSTexture - fstat failed, fname = " << fname <<
      ", " << strerror(errno) << std::endl;
    return false;
  }

  size_t fsize = (size_t)st.st_size;
  if(fsize < DDS_HEADER_SIZE) {
    std::cout << "ERROR: loadDDSTexture failed, fname = " << fname <<
      ", fsize = " << fsize << ", less then DDS_HEADER_SIZE (" << DDS_HEADER_SIZE << ")" << std::endl;
    return false;
  }

  unsigned char* dataPtr = (unsigned char*)mmap(nullptr, fsize, PROT_READ, MAP_PRIVATE | MAP_POPULATE, fd, 0);
  if(dataPtr == MAP_FAILED) {
    std::cout << "ERROR: loadDDSTexture - mmap failed, fname = " << fname <<
      ", " << strerror(errno) << std::endl;
    return false;
  }
  defer(munmap(dataPtr, fsize));

  unsigned int signature    = *(unsigned int*)&(dataPtr[ 0]);
  unsigned int height       = *(unsigned int*)&(dataPtr[12]);
  unsigned int width        = *(unsigned int*)&(dataPtr[16]);
  unsigned int mipMapNumber = *(unsigned int*)&(dataPtr[28]);
  unsigned int formatCode   = *(unsigned int*)&(dataPtr[84]);

  if(signature != DDS_SIGNATURE) {
    std::cout << "ERROR: loadDDSTexture failed, fname = " << fname <<
      "invalid signature: 0x" << std::hex << signature << std::endl;
    return false;
  }

  unsigned int format;
  switch(formatCode)
  {
    case FORMAT_CODE_DXT1:
      format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
      break;
    case FORMAT_CODE_DXT3:
      format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
      break;
    case FORMAT_CODE_DXT5:
      format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
      break;
    default:
      std::cout << "ERROR: loadDDSTexture failed, fname = " << fname <<
        ", unknown formatCode: 0x" << std::hex << formatCode << std::endl;
      return false;
  }

  glBindTexture(GL_TEXTURE_2D, textureId);
  glPixelStorei(GL_UNPACK_ALIGNMENT,1);

  unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
  unsigned int offset = DDS_HEADER_SIZE;

  // load mipmaps
  for (unsigned int level = 0; level < mipMapNumber; ++level)
  {
    unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
    if(fsize < offset + size) {
      std::cout << "ERROR: loadDDSTexture failed, fname = " << fname <<
        ", fsize = " << fsize << ", level = " << level <<
        ", offset = " << offset << ", size = " << size << std::endl;
      return false;
    }
    glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, dataPtr + offset);

    width = width > 1 ? width >> 1 : 1;
    height = height > 1 ? height >> 1 : 1;
    offset += size;
  }

 // glBindTexture(GL_TEXTURE_2D, 0); // unbind
  return true;
}

bool checkShaderCompileStatus(GLuint obj) {
  GLint status;
  glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
  if(status == GL_FALSE) {
    GLint length;
    glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &length);
    std::vector<char> log((unsigned long)length);
    glGetShaderInfoLog(obj, length, &length, &log[0]);
    std::cerr << &log[0];
    return true;
  }
  return false;
}

bool checkProgramLinkStatus(GLuint obj) {
  GLint status;
  glGetProgramiv(obj, GL_LINK_STATUS, &status);
  if(status == GL_FALSE) {
    GLint length;
    glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &length);
    std::vector<char> log((unsigned long) length);
    glGetProgramInfoLog(obj, length, &length, &log[0]);
    std::cerr << &log[0];
    return true;
  }
  return false;
}

GLuint loadShader(char const *fname, GLenum shaderType, bool *errorFlagPtr) {
  std::ifstream fileStream(fname);
  std::stringstream buffer;
  buffer << fileStream.rdbuf();
  std::string shaderSource(buffer.str());

  GLuint shaderId = glCreateShader(shaderType);
  const GLchar * const shaderSourceCStr = shaderSource.c_str();

  glShaderSource(shaderId, 1, &shaderSourceCStr, nullptr);
  glCompileShader(shaderId);

  *errorFlagPtr = checkShaderCompileStatus(shaderId);
  if(*errorFlagPtr) {
    glDeleteShader(shaderId);
    return 0;
  }

  return shaderId;
}

GLuint prepareProgram(const std::vector<GLuint>& shaders, bool *errorFlagPtr) {
  *errorFlagPtr = false;

  GLuint programId = glCreateProgram();
  for(auto it = shaders.cbegin(); it != shaders.cend(); ++it) {
    glAttachShader(programId, *it);
  }
  glLinkProgram(programId);

  *errorFlagPtr = checkProgramLinkStatus(programId);
  if(*errorFlagPtr) {
    glDeleteProgram(programId);
    return 0;
  }

  return programId;
}
<commit_msg>There is no MAP_POPILATE on Mac<commit_after>#include "utils.h"
// <GL/glext.h> on Linux, <OpenGL/glext.h> on MacOS :(
#include "../glfw/deps/GL/glext.h"

#include <glm/glm.hpp>
#include <glm/gtc/type_ptr.hpp>
#include <iostream>
#include <sstream>
#include <fstream>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <defer.h>
#include <unistd.h>
#include <stb_image.h>

void flipTexture(unsigned char *textureData, int width, int height, int n) {
  for(int h = 0; h < height/2; ++h) {
    for(int w = 0; w < width; ++w) {
      for(int i = 0; i < n; ++i) {
        int offset1 = (h*width + w)*n + i;
        int offset2 = ((height - h - 1)*width + w)*n + i;
        unsigned char t = textureData[offset1];
        textureData[offset1] = textureData[offset2];
        textureData[offset2] = t;
      }
    }
  }
}

bool loadCommonTexture(char const* fname, GLuint textureId) {
  return loadCommonTextureExt(fname, textureId, false);
}

bool loadCommonTextureExt(char const* fname, GLuint textureId, bool flip) {
  int width, height, n;
  unsigned char *textureData = stbi_load(fname, &width, &height, &n, 0);
  if(textureData == nullptr) {
    std::cout << "ERROR: loadCommonTextureExt failed, fname = " << fname << ", stbi_load returned nullptr" << std::endl;
    return false;
  }
  defer(stbi_image_free(textureData));

  if(flip) flipTexture(textureData, width, height, n);

  glBindTexture(GL_TEXTURE_2D, textureId);
  glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, textureData);

  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

  // Generate mipmaps
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
  glGenerateMipmap(GL_TEXTURE_2D);

  // glBindTexture(GL_TEXTURE_2D, 0); // unbind
  return true;
}

#define DDS_HEADER_SIZE 128
#define DDS_SIGNATURE    0x20534444 // "DDS "
#define FORMAT_CODE_DXT1 0x31545844 // "DXT1"
#define FORMAT_CODE_DXT3 0x33545844 // "DXT3"
#define FORMAT_CODE_DXT5 0x35545844 // "DXT5"

bool loadDDSTexture(char const *fname, GLuint textureId) {
  int fd = open(fname, O_RDONLY, 0);
  if(fd < 0) {
    std::cout << "ERROR: loadDDSTexture - open failed, fname =  " << fname <<
      ", " << strerror(errno) << std::endl;
    return false;
  }
  defer(close(fd));

  struct stat st;
  if(fstat(fd, &st) < 0) {
    std::cout << "ERROR: loadDDSTexture - fstat failed, fname = " << fname <<
      ", " << strerror(errno) << std::endl;
    return false;
  }

  size_t fsize = (size_t)st.st_size;
  if(fsize < DDS_HEADER_SIZE) {
    std::cout << "ERROR: loadDDSTexture failed, fname = " << fname <<
      ", fsize = " << fsize << ", less then DDS_HEADER_SIZE (" << DDS_HEADER_SIZE << ")" << std::endl;
    return false;
  }

  unsigned char* dataPtr = (unsigned char*)mmap(nullptr, fsize, PROT_READ, MAP_PRIVATE, fd, 0);
  if(dataPtr == MAP_FAILED) {
    std::cout << "ERROR: loadDDSTexture - mmap failed, fname = " << fname <<
      ", " << strerror(errno) << std::endl;
    return false;
  }
  defer(munmap(dataPtr, fsize));

  unsigned int signature    = *(unsigned int*)&(dataPtr[ 0]);
  unsigned int height       = *(unsigned int*)&(dataPtr[12]);
  unsigned int width        = *(unsigned int*)&(dataPtr[16]);
  unsigned int mipMapNumber = *(unsigned int*)&(dataPtr[28]);
  unsigned int formatCode   = *(unsigned int*)&(dataPtr[84]);

  if(signature != DDS_SIGNATURE) {
    std::cout << "ERROR: loadDDSTexture failed, fname = " << fname <<
      "invalid signature: 0x" << std::hex << signature << std::endl;
    return false;
  }

  unsigned int format;
  switch(formatCode)
  {
    case FORMAT_CODE_DXT1:
      format = GL_COMPRESSED_RGBA_S3TC_DXT1_EXT;
      break;
    case FORMAT_CODE_DXT3:
      format = GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
      break;
    case FORMAT_CODE_DXT5:
      format = GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
      break;
    default:
      std::cout << "ERROR: loadDDSTexture failed, fname = " << fname <<
        ", unknown formatCode: 0x" << std::hex << formatCode << std::endl;
      return false;
  }

  glBindTexture(GL_TEXTURE_2D, textureId);
  glPixelStorei(GL_UNPACK_ALIGNMENT,1);

  unsigned int blockSize = (format == GL_COMPRESSED_RGBA_S3TC_DXT1_EXT) ? 8 : 16;
  unsigned int offset = DDS_HEADER_SIZE;

  // load mipmaps
  for (unsigned int level = 0; level < mipMapNumber; ++level)
  {
    unsigned int size = ((width+3)/4)*((height+3)/4)*blockSize;
    if(fsize < offset + size) {
      std::cout << "ERROR: loadDDSTexture failed, fname = " << fname <<
        ", fsize = " << fsize << ", level = " << level <<
        ", offset = " << offset << ", size = " << size << std::endl;
      return false;
    }
    glCompressedTexImage2D(GL_TEXTURE_2D, level, format, width, height, 0, size, dataPtr + offset);

    width = width > 1 ? width >> 1 : 1;
    height = height > 1 ? height >> 1 : 1;
    offset += size;
  }

 // glBindTexture(GL_TEXTURE_2D, 0); // unbind
  return true;
}

bool checkShaderCompileStatus(GLuint obj) {
  GLint status;
  glGetShaderiv(obj, GL_COMPILE_STATUS, &status);
  if(status == GL_FALSE) {
    GLint length;
    glGetShaderiv(obj, GL_INFO_LOG_LENGTH, &length);
    std::vector<char> log((unsigned long)length);
    glGetShaderInfoLog(obj, length, &length, &log[0]);
    std::cerr << &log[0];
    return true;
  }
  return false;
}

bool checkProgramLinkStatus(GLuint obj) {
  GLint status;
  glGetProgramiv(obj, GL_LINK_STATUS, &status);
  if(status == GL_FALSE) {
    GLint length;
    glGetProgramiv(obj, GL_INFO_LOG_LENGTH, &length);
    std::vector<char> log((unsigned long) length);
    glGetProgramInfoLog(obj, length, &length, &log[0]);
    std::cerr << &log[0];
    return true;
  }
  return false;
}

GLuint loadShader(char const *fname, GLenum shaderType, bool *errorFlagPtr) {
  std::ifstream fileStream(fname);
  std::stringstream buffer;
  buffer << fileStream.rdbuf();
  std::string shaderSource(buffer.str());

  GLuint shaderId = glCreateShader(shaderType);
  const GLchar * const shaderSourceCStr = shaderSource.c_str();

  glShaderSource(shaderId, 1, &shaderSourceCStr, nullptr);
  glCompileShader(shaderId);

  *errorFlagPtr = checkShaderCompileStatus(shaderId);
  if(*errorFlagPtr) {
    glDeleteShader(shaderId);
    return 0;
  }

  return shaderId;
}

GLuint prepareProgram(const std::vector<GLuint>& shaders, bool *errorFlagPtr) {
  *errorFlagPtr = false;

  GLuint programId = glCreateProgram();
  for(auto it = shaders.cbegin(); it != shaders.cend(); ++it) {
    glAttachShader(programId, *it);
  }
  glLinkProgram(programId);

  *errorFlagPtr = checkProgramLinkStatus(programId);
  if(*errorFlagPtr) {
    glDeleteProgram(programId);
    return 0;
  }

  return programId;
}
<|endoftext|>


<commit_before>#include <vnl/vnl_matrix_fixed.txx>
template class vnl_matrix_fixed<double,1,1>;
<commit_msg>BUG: This source should use VNL_MATRIX_FIXED_INSTANTIATE to create the instantiation.<commit_after>#include <vnl/vnl_matrix_fixed.txx>
VNL_MATRIX_FIXED_INSTANTIATE(double,1,1);
<|endoftext|>


<commit_before>/***********************************************
    Copyright (C) 2014  Schutz Sacha
    This file is part of QJsonModel (https://github.com/dridk/QJsonmodel).

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

    QJsonModel 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 QJsonModel.  If not, see <http://www.gnu.org/licenses/>.

**********************************************/

#include "qjsonmodel.h"
#include <QFile>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QIcon>
#include <QFont>

QJsonModel::QJsonModel(QObject *parent) :
    QAbstractItemModel(parent)
{
    mRootItem = new QJsonTreeItem;
    mHeaders.append("key");
    mHeaders.append("value");

}

bool QJsonModel::load(const QString &fileName)
{
    QFile file(fileName);
    bool success = false;
    if (file.open(QIODevice::ReadOnly)) {
        success = load(&file);
        file.close();
    }
    else success = false;

    return success;
}

bool QJsonModel::load(QIODevice *device)
{
    return loadJson(device->readAll());
}

bool QJsonModel::loadJson(const QByteArray &json)
{
    mDocument = QJsonDocument::fromJson(json);

    if (!mDocument.isNull())
    {
        beginResetModel();
        mRootItem = QJsonTreeItem::load(QJsonValue(mDocument.object()));
        endResetModel();
        return true;
    }
    return false;
}

QVariant QJsonModel::data(const QModelIndex &index, int role) const
{

    if (!index.isValid())
        return QVariant();

    QJsonTreeItem *item = static_cast<QJsonTreeItem*>(index.internalPointer());

    if ((role == Qt::DecorationRole) && (index.column() == 0)){

        return mTypeIcons.value(item->type());
    }

    if (role == Qt::DisplayRole) {

        if (index.column() == 0)
            return QString("%1").arg(item->key());

        if (index.column() == 1)
            return QString("%1").arg(item->value());
    }

    return QVariant();

}

QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();

    if (orientation == Qt::Horizontal) {

        return mHeaders.value(section);
    }
    else
        return QVariant();
}

QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    QJsonTreeItem *parentItem;

    if (!parent.isValid())
        parentItem = mRootItem;
    else
        parentItem = static_cast<QJsonTreeItem*>(parent.internalPointer());

    QJsonTreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}

QModelIndex QJsonModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    QJsonTreeItem *childItem = static_cast<QJsonTreeItem*>(index.internalPointer());
    QJsonTreeItem *parentItem = childItem->parent();

    if (parentItem == mRootItem)
        return QModelIndex();

    return createIndex(parentItem->row(), 0, parentItem);
}

int QJsonModel::rowCount(const QModelIndex &parent) const
{
    QJsonTreeItem *parentItem;
    if (parent.column() > 0)
        return 0;

    if (!parent.isValid())
        parentItem = mRootItem;
    else
        parentItem = static_cast<QJsonTreeItem*>(parent.internalPointer());

    return parentItem->childCount();
}

int QJsonModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return 2;
}

void QJsonModel::setIcon(const QJsonValue::Type &type, const QIcon &icon)
{
    mTypeIcons.insert(type,icon);
}
<commit_msg>Load root item either from array or object<commit_after>/***********************************************
    Copyright (C) 2014  Schutz Sacha
    This file is part of QJsonModel (https://github.com/dridk/QJsonmodel).

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

    QJsonModel 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 QJsonModel.  If not, see <http://www.gnu.org/licenses/>.

**********************************************/

#include "qjsonmodel.h"
#include <QFile>
#include <QDebug>
#include <QJsonDocument>
#include <QJsonObject>
#include <QIcon>
#include <QFont>

QJsonModel::QJsonModel(QObject *parent) :
    QAbstractItemModel(parent)
{
    mRootItem = new QJsonTreeItem;
    mHeaders.append("key");
    mHeaders.append("value");

}

bool QJsonModel::load(const QString &fileName)
{
    QFile file(fileName);
    bool success = false;
    if (file.open(QIODevice::ReadOnly)) {
        success = load(&file);
        file.close();
    }
    else success = false;

    return success;
}

bool QJsonModel::load(QIODevice *device)
{
    return loadJson(device->readAll());
}

bool QJsonModel::loadJson(const QByteArray &json)
{
    mDocument = QJsonDocument::fromJson(json);

    if (!mDocument.isNull())
    {
        beginResetModel();
        if (mDocument.isArray()) {
            mRootItem = QJsonTreeItem::load(QJsonValue(mDocument.array()));
        } else {
            mRootItem = QJsonTreeItem::load(QJsonValue(mDocument.object()));
        }
        endResetModel();
        return true;
    }
    return false;
}

QVariant QJsonModel::data(const QModelIndex &index, int role) const
{

    if (!index.isValid())
        return QVariant();

    QJsonTreeItem *item = static_cast<QJsonTreeItem*>(index.internalPointer());

    if ((role == Qt::DecorationRole) && (index.column() == 0)){

        return mTypeIcons.value(item->type());
    }

    if (role == Qt::DisplayRole) {

        if (index.column() == 0)
            return QString("%1").arg(item->key());

        if (index.column() == 1)
            return QString("%1").arg(item->value());
    }

    return QVariant();

}

QVariant QJsonModel::headerData(int section, Qt::Orientation orientation, int role) const
{
    if (role != Qt::DisplayRole)
        return QVariant();

    if (orientation == Qt::Horizontal) {

        return mHeaders.value(section);
    }
    else
        return QVariant();
}

QModelIndex QJsonModel::index(int row, int column, const QModelIndex &parent) const
{
    if (!hasIndex(row, column, parent))
        return QModelIndex();

    QJsonTreeItem *parentItem;

    if (!parent.isValid())
        parentItem = mRootItem;
    else
        parentItem = static_cast<QJsonTreeItem*>(parent.internalPointer());

    QJsonTreeItem *childItem = parentItem->child(row);
    if (childItem)
        return createIndex(row, column, childItem);
    else
        return QModelIndex();
}

QModelIndex QJsonModel::parent(const QModelIndex &index) const
{
    if (!index.isValid())
        return QModelIndex();

    QJsonTreeItem *childItem = static_cast<QJsonTreeItem*>(index.internalPointer());
    QJsonTreeItem *parentItem = childItem->parent();

    if (parentItem == mRootItem)
        return QModelIndex();

    return createIndex(parentItem->row(), 0, parentItem);
}

int QJsonModel::rowCount(const QModelIndex &parent) const
{
    QJsonTreeItem *parentItem;
    if (parent.column() > 0)
        return 0;

    if (!parent.isValid())
        parentItem = mRootItem;
    else
        parentItem = static_cast<QJsonTreeItem*>(parent.internalPointer());

    return parentItem->childCount();
}

int QJsonModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return 2;
}

void QJsonModel::setIcon(const QJsonValue::Type &type, const QIcon &icon)
{
    mTypeIcons.insert(type,icon);
}
<|endoftext|>


<commit_before>/**
 * kmcomposereditor.cpp
 *
 * Copyright (C)  2007, 2008 Laurent Montel <montel@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include "kmcomposereditor.h"
#include "kmcomposewin.h"
#include "kmcommands.h"
#include "kmmsgdict.h"
#include "kmfolder.h"
#include "maillistdrag.h"

#include <kmime/kmime_codecs.h>
#include <KPIMTextEdit/EMailQuoteHighlighter>

#include <KAction>
#include <KActionCollection>
#include <KFileDialog>
#include <KLocale>
#include <KMenu>
#include <KMessageBox>
#include <KPushButton>

#include <QBuffer>
#include <QClipboard>
#include <QDropEvent>
#include <QFileInfo>

KMComposerEditor::KMComposerEditor( KMComposeWin *win,QWidget *parent)
 :KMeditor(parent),m_composerWin(win)
{
}

KMComposerEditor::~KMComposerEditor()
{
}

void KMComposerEditor::createActions( KActionCollection *actionCollection )
{
  KMeditor::createActions( actionCollection );

  mPasteQuotation = new KAction( i18n("Pa&ste as Quotation"), this );
  actionCollection->addAction("paste_quoted", mPasteQuotation );
  connect( mPasteQuotation, SIGNAL(triggered(bool) ), this, SLOT( slotPasteAsQuotation()) );

  mAddQuoteChars = new KAction( i18n("Add &Quote Characters"), this );
  actionCollection->addAction( "tools_quote", mAddQuoteChars );
  connect( mAddQuoteChars, SIGNAL(triggered(bool) ), this, SLOT(slotAddQuotes()) );

  mRemQuoteChars = new KAction( i18n("Re&move Quote Characters"), this );
  actionCollection->addAction( "tools_unquote", mRemQuoteChars );
  connect (mRemQuoteChars, SIGNAL(triggered(bool) ), this, SLOT(slotRemoveQuotes()) );
}

void KMComposerEditor::setHighlighterColors(KPIMTextEdit::EMailQuoteHighlighter * highlighter)
{
  // defaults from kmreaderwin.cpp. FIXME: centralize somewhere.
  QColor color1( 0x00, 0x80, 0x00 );
  QColor color2( 0x00, 0x70, 0x00 );
  QColor color3( 0x00, 0x60, 0x00 );
  QColor misspelled = Qt::red;

  if ( !GlobalSettings::self()->useDefaultColors() ) {
    KConfigGroup readerConfig( KMKernel::config(), "Reader" );
    color3 = readerConfig.readEntry( "QuotedText3", color3  );
    color2 = readerConfig.readEntry( "QuotedText2", color2  );
    color1 = readerConfig.readEntry( "QuotedText1", color1  );
    misspelled = readerConfig.readEntry( "MisspelledColor", misspelled );
  }

  highlighter->setQuoteColor( Qt::black /* ignored anyway */,
                              color3, color2, color1, misspelled );
}

QString KMComposerEditor::smartQuote( const QString & msg )
{
  return m_composerWin->smartQuote( msg );
}

const QString KMComposerEditor::defaultQuoteSign() const
{
  if ( !m_quotePrefix.simplified().isEmpty() )
    return m_quotePrefix;
  else
    return KPIMTextEdit::TextEdit::defaultQuoteSign();
}

int KMComposerEditor::quoteLength( const QString& line ) const
{
  if ( !m_quotePrefix.simplified().isEmpty() ) {
    if ( line.startsWith( m_quotePrefix ) )
      return m_quotePrefix.length();
    else
      return 0;
  }
  else
    return KPIMTextEdit::TextEdit::quoteLength( line );
}

void KMComposerEditor::setQuotePrefixName( const QString &quotePrefix )
{
  m_quotePrefix = quotePrefix;
}

QString KMComposerEditor::quotePrefixName() const
{
  if ( !m_quotePrefix.simplified().isEmpty() )
    return m_quotePrefix;
  else
    return ">";
}

void KMComposerEditor::replaceUnknownChars( const QTextCodec *codec )
{
  QTextCursor cursor( document() );
  cursor.beginEditBlock();
  while ( !cursor.atEnd() ) {
    cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor );
    QChar cur = cursor.selectedText().at( 0 );
    if ( !codec->canEncode( cur ) ) {
      cursor.insertText( "?" );
    }
    else {
      cursor.clearSelection();
    }
  }
  cursor.endEditBlock();
}

bool KMComposerEditor::canInsertFromMimeData( const QMimeData *source ) const
{
  if ( KPIM::MailList::canDecode( source ) )
    return true;
  if ( source->hasFormat( "text/x-kmail-textsnippet" ) )
    return true;
  if ( source->hasUrls() )
    return true;

  return KPIMTextEdit::TextEdit::canInsertFromMimeData( source );
}

void KMComposerEditor::insertFromMimeData( const QMimeData *source )
{
    // If this is a list of mails, attach those mails as forwards.
  if ( KPIM::MailList::canDecode( source ) ) {

    // Decode the list of serial numbers stored as the drag data
    QByteArray serNums = KPIM::MailList::serialsFromMimeData( source );
    QBuffer serNumBuffer( &serNums );
    serNumBuffer.open( QIODevice::ReadOnly );
    QDataStream serNumStream( &serNumBuffer );
    quint32 serNum;
    KMFolder *folder = 0;
    int idx;
    QList<KMMsgBase*> messageList;
    while ( !serNumStream.atEnd() ) {
      KMMsgBase *msgBase = 0;
      serNumStream >> serNum;
      KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
      if ( folder ) {
        msgBase = folder->getMsgBase( idx );
      }
      if ( msgBase ) {
        messageList.append( msgBase );
      }
    }
    serNumBuffer.close();
    uint identity = folder ? folder->identity() : 0;
    KMCommand *command = new KMForwardAttachedCommand( m_composerWin, messageList,
                                                       identity, m_composerWin );
    command->start();
    return;
  }

  if ( source->hasFormat( "text/x-kmail-textsnippet" ) ) {
    emit insertSnippet();
    return;
  }

  // If this is a URL list, add those files as attachments or text
  const KUrl::List urlList = KUrl::List::fromMimeData( source );
  if ( !urlList.isEmpty() ) {
    KMenu p;
    const QAction *addAsTextAction = p.addAction( i18n("Add as &Text") );
    const QAction *addAsAttachmentAction = p.addAction( i18n("Add as &Attachment") );
    const QAction *selectedAction = p.exec( QCursor::pos() );
    if ( selectedAction == addAsTextAction ) {
      foreach( const KUrl &url, urlList ) {
        textCursor().insertText(url.url());
      }
    } else if ( selectedAction == addAsAttachmentAction ) {
      foreach( const KUrl &url, urlList ) {
        m_composerWin->addAttach( url );
      }
    }
    return;
  }

  KPIMTextEdit::TextEdit::insertFromMimeData(source);
}

#include "kmcomposereditor.moc"
<commit_msg>Bring back the ability to drag images from KSnapshot and add them as attachments.<commit_after>/**
 * kmcomposereditor.cpp
 *
 * Copyright (C)  2007, 2008 Laurent Montel <montel@kde.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301  USA
 */

#include "kmcomposereditor.h"
#include "kmcomposewin.h"
#include "kmcommands.h"
#include "kmmsgdict.h"
#include "kmfolder.h"
#include "maillistdrag.h"

#include <kmime/kmime_codecs.h>
#include <KPIMTextEdit/EMailQuoteHighlighter>

#include <KAction>
#include <KActionCollection>
#include <KFileDialog>
#include <KLocale>
#include <KMenu>
#include <KMessageBox>
#include <KPushButton>
#include <KInputDialog>

#include <QBuffer>
#include <QClipboard>
#include <QDropEvent>
#include <QFileInfo>

KMComposerEditor::KMComposerEditor( KMComposeWin *win,QWidget *parent)
 :KMeditor(parent),m_composerWin(win)
{
}

KMComposerEditor::~KMComposerEditor()
{
}

void KMComposerEditor::createActions( KActionCollection *actionCollection )
{
  KMeditor::createActions( actionCollection );

  mPasteQuotation = new KAction( i18n("Pa&ste as Quotation"), this );
  actionCollection->addAction("paste_quoted", mPasteQuotation );
  connect( mPasteQuotation, SIGNAL(triggered(bool) ), this, SLOT( slotPasteAsQuotation()) );

  mAddQuoteChars = new KAction( i18n("Add &Quote Characters"), this );
  actionCollection->addAction( "tools_quote", mAddQuoteChars );
  connect( mAddQuoteChars, SIGNAL(triggered(bool) ), this, SLOT(slotAddQuotes()) );

  mRemQuoteChars = new KAction( i18n("Re&move Quote Characters"), this );
  actionCollection->addAction( "tools_unquote", mRemQuoteChars );
  connect (mRemQuoteChars, SIGNAL(triggered(bool) ), this, SLOT(slotRemoveQuotes()) );
}

void KMComposerEditor::setHighlighterColors(KPIMTextEdit::EMailQuoteHighlighter * highlighter)
{
  // defaults from kmreaderwin.cpp. FIXME: centralize somewhere.
  QColor color1( 0x00, 0x80, 0x00 );
  QColor color2( 0x00, 0x70, 0x00 );
  QColor color3( 0x00, 0x60, 0x00 );
  QColor misspelled = Qt::red;

  if ( !GlobalSettings::self()->useDefaultColors() ) {
    KConfigGroup readerConfig( KMKernel::config(), "Reader" );
    color3 = readerConfig.readEntry( "QuotedText3", color3  );
    color2 = readerConfig.readEntry( "QuotedText2", color2  );
    color1 = readerConfig.readEntry( "QuotedText1", color1  );
    misspelled = readerConfig.readEntry( "MisspelledColor", misspelled );
  }

  highlighter->setQuoteColor( Qt::black /* ignored anyway */,
                              color3, color2, color1, misspelled );
}

QString KMComposerEditor::smartQuote( const QString & msg )
{
  return m_composerWin->smartQuote( msg );
}

const QString KMComposerEditor::defaultQuoteSign() const
{
  if ( !m_quotePrefix.simplified().isEmpty() )
    return m_quotePrefix;
  else
    return KPIMTextEdit::TextEdit::defaultQuoteSign();
}

int KMComposerEditor::quoteLength( const QString& line ) const
{
  if ( !m_quotePrefix.simplified().isEmpty() ) {
    if ( line.startsWith( m_quotePrefix ) )
      return m_quotePrefix.length();
    else
      return 0;
  }
  else
    return KPIMTextEdit::TextEdit::quoteLength( line );
}

void KMComposerEditor::setQuotePrefixName( const QString &quotePrefix )
{
  m_quotePrefix = quotePrefix;
}

QString KMComposerEditor::quotePrefixName() const
{
  if ( !m_quotePrefix.simplified().isEmpty() )
    return m_quotePrefix;
  else
    return ">";
}

void KMComposerEditor::replaceUnknownChars( const QTextCodec *codec )
{
  QTextCursor cursor( document() );
  cursor.beginEditBlock();
  while ( !cursor.atEnd() ) {
    cursor.movePosition( QTextCursor::NextCharacter, QTextCursor::KeepAnchor );
    QChar cur = cursor.selectedText().at( 0 );
    if ( !codec->canEncode( cur ) ) {
      cursor.insertText( "?" );
    }
    else {
      cursor.clearSelection();
    }
  }
  cursor.endEditBlock();
}

bool KMComposerEditor::canInsertFromMimeData( const QMimeData *source ) const
{
  if ( source->hasImage() && source->hasFormat( "image/png" ) )
    return true;
  if ( KPIM::MailList::canDecode( source ) )
    return true;
  if ( source->hasFormat( "text/x-kmail-textsnippet" ) )
    return true;
  if ( source->hasUrls() )
    return true;

  return KPIMTextEdit::TextEdit::canInsertFromMimeData( source );
}

void KMComposerEditor::insertFromMimeData( const QMimeData *source )
{
  // If this is a PNG image, either add it as an attachment or as an inline image
  if ( source->hasImage() && source->hasFormat( "image/png" ) ) {
    if ( textMode() == KRichTextEdit::Rich ) {
      KMenu menu;
      const QAction *addAsInlineImageAction = menu.addAction( i18n("Add as &Inline Image") );
      /*const QAction *addAsAttachmentAction = */menu.addAction( i18n("Add as &Attachment") );
      const QAction *selectedAction = menu.exec( QCursor::pos() );
      if ( selectedAction == addAsInlineImageAction ) {
        // Let the textedit from kdepimlibs handle inline images
        KPIMTextEdit::TextEdit::insertFromMimeData( source );
        return;
      }
      // else fall through
    }

    // Ok, when we reached this point, the user wants to add the image as an attachment.
    // Ask for the filename first.
    bool ok;
    const QString attName =
       KInputDialog::getText( "KMail", i18n( "Name of the attachment:" ), QString(), &ok, this );
    if ( !ok ) {
      return;
    }

    const QByteArray imageData = source->data( "image/png" );
    m_composerWin->addAttachment( attName, "base64", imageData, "image", "png", QByteArray(),
                                  QString(), QByteArray() );
    return;
  }

    // If this is a list of mails, attach those mails as forwards.
  if ( KPIM::MailList::canDecode( source ) ) {

    // Decode the list of serial numbers stored as the drag data
    QByteArray serNums = KPIM::MailList::serialsFromMimeData( source );
    QBuffer serNumBuffer( &serNums );
    serNumBuffer.open( QIODevice::ReadOnly );
    QDataStream serNumStream( &serNumBuffer );
    quint32 serNum;
    KMFolder *folder = 0;
    int idx;
    QList<KMMsgBase*> messageList;
    while ( !serNumStream.atEnd() ) {
      KMMsgBase *msgBase = 0;
      serNumStream >> serNum;
      KMMsgDict::instance()->getLocation( serNum, &folder, &idx );
      if ( folder ) {
        msgBase = folder->getMsgBase( idx );
      }
      if ( msgBase ) {
        messageList.append( msgBase );
      }
    }
    serNumBuffer.close();
    uint identity = folder ? folder->identity() : 0;
    KMCommand *command = new KMForwardAttachedCommand( m_composerWin, messageList,
                                                       identity, m_composerWin );
    command->start();
    return;
  }

  if ( source->hasFormat( "text/x-kmail-textsnippet" ) ) {
    emit insertSnippet();
    return;
  }

  // If this is a URL list, add those files as attachments or text
  const KUrl::List urlList = KUrl::List::fromMimeData( source );
  if ( !urlList.isEmpty() ) {
    KMenu p;
    const QAction *addAsTextAction = p.addAction( i18n("Add as &Text") );
    const QAction *addAsAttachmentAction = p.addAction( i18n("Add as &Attachment") );
    const QAction *selectedAction = p.exec( QCursor::pos() );
    if ( selectedAction == addAsTextAction ) {
      foreach( const KUrl &url, urlList ) {
        textCursor().insertText(url.url());
      }
    } else if ( selectedAction == addAsAttachmentAction ) {
      foreach( const KUrl &url, urlList ) {
        m_composerWin->addAttach( url );
      }
    }
    return;
  }

  KPIMTextEdit::TextEdit::insertFromMimeData( source );
}

#include "kmcomposereditor.moc"
<|endoftext|>


<commit_before><commit_msg>sorted_vector: removing the vector::ersase makes more sense<commit_after><|endoftext|>