Примеры моего кода на C++

1. Консольное приложение - построение файла различий между двумя произвольными

    текстовыми файлами (исходным и полученным после редактирования),

    применение файла различий (обратное получение исходного файла).

    исходный файл-source file

    файл после редактирования-target file

    файл изменений-changeset file

 

 

файл difr.h

 

//---------------------------------------------------------------------------

// SCCS

// Обработка изменений в текстовых файлах

// (c) Vladimir Mishenin

// email: bobm@mail.ru

 

#ifndef difrH

#define difrH

 

#include <stdio.h>

#include <vector>

#include <string>

#include <list>

 

//---------------------------------------------------------------------------

 

namespace Difference {

 

//макс длина строки

static const int MAXSIZESTR = 4096;

//длина контекста

static const int EXSIZECTX = 1;

 

//---------------------------------------------------------------------------

//эл-т для хранения в контейнере

struct StrItem {

  std::string sval;

};

 

//эл-т для хранения в контейнере

struct StrExtItem {

  StrExtItem(void) { shash = 0.; }

  void CalcHash(void);

 

  std::string sval;

  double shash;

};

 

//---------------------------------------------------------------------------

//базовый шаблонный класс контейнера с ф-ями ввода/вывода

template <typename item>

class IOcont {

public:

  std::vector<item> Items;

 

  bool ReadItems(const char* fn);

  bool WriteItems(const char* fn);

 

  virtual ~IOcont(void) { Items.clear(); }

};

 

//прочитать строки из файла fn в контейнер

template <typename item>

bool IOcont<item>::ReadItems(const char* fn)

{

  FILE* fl;

  if((fl = fopen(fn, "rt")) != NULL) {

    char buf[MAXSIZESTR];

    int len;

    item itm;

 

    while(fgets(buf, MAXSIZESTR, fl)) {

      len = (int)strlen(buf);

      if(len > 0) {

        while(buf[len-1] == '\n' || buf[len-1] == '\r') {

          buf[len-1] = 0;

          if(--len < 1) break;

        }

      }

      itm.sval = buf;

      Items.push_back(itm);

    }

 

    fclose(fl);

    return true;

  }

 

  return false;

}

 

//записать строки из контейнера в файл fn

template <typename item>

bool IOcont<item>::WriteItems(const char* fn)

{

  FILE* fl;

  if((fl = fopen(fn, "wt")) != NULL) {

 

    for(std::vector<item>::iterator it = Items.begin();

      it!= Items.end(); ++it) {

 

      fputs(it->sval.c_str(), fl);

      fputs("\n", fl);

    }

 

    fclose(fl);

    return true;

  }

 

  return false;

}

 

//---------------------------------------------------------------------------

//производные классы контейнеров

 

//класс хранения текста

class DataCont : public IOcont<StrExtItem> {

public:

  void CalcHashAll(void);

  int FindContext(const DataCont &ctx, int &idxbeg, bool beg = false) const;

};

 

//класс описатель действия

struct Action {

  Action(void) { beg = false; act = 0; }

  bool IsOk(void);

  void Clear(void);

 

  char act;       //I-insert D-delete R-replace

  DataCont after; //блок AFTER

  bool beg;       //контекст after дб строго от начала

  DataCont dt1;   //блок INSERT DELETE REPLACE

  DataCont dt2;   //блок ON (для REPLACE)

};

//последовательность действий

typedef std::list<Action> Actions;

 

//класс хранения комманд

class CmdCont : public IOcont<StrItem> {

  public:

  void Actions2Cmd(const Actions &a);

  void Cmd2Actions(Actions &a);

 

  private:

  void CopyVec(const DataCont &vec);

  StrItem cmd;

};

 

//---------------------------------------------------------------------------

//класс-оболочка задачи

class Difr {

  DataCont inp;

  DataCont out;

  CmdCont cmd;

  const char* errstr;

 

  bool CreateCmdProc(Actions &a);

  bool ApplyCmdProc(Actions &a);

  void WriteAction(int iix, int iox, int iframex, int oframex, Actions &a);

  void WriteContext(int oframe, Action &act);

 

public:

  Difr(void);

  virtual ~Difr(void);

  bool CreateCmd(const char* inpfn, const char* outfn, const char* cmdfn);

  bool ApplyCmd(const char* inpfn, const char* outfn, const char* cmdfn);

  const char* GetLastError(void);

};

 

}; //namespace Difference

 

#endif

 

 

файл difr.cpp

 

//---------------------------------------------------------------------------

// SCCS

// Обработка изменений в текстовых файлах

// (c) Vladimir Mishenin

// email: bobm@mail.ru

 

#include "stdafx.h"

#include "difr.h"

 

//---------------------------------------------------------------------------

 

namespace Difference {

 

//---------------------------------------------------------------------------

//посчитать shash для строки sval

void StrExtItem::CalcHash(void)

{

  const double e = 1.1111111;

 

  int l = (int)sval.size();

  shash = 0.;

 

  for(int i = 0; i < l; ++i)

    shash += sval[i] * (i+1) * e;

}

 

//---------------------------------------------------------------------------

//посчитать shash для всех строк контейнера

void DataCont::CalcHashAll(void)

{

  for(std::vector<StrExtItem>::iterator it = Items.begin();

    it != Items.end(); ++it) it->CalcHash();

}

 

//найти в Items контекст ctx, в idxbeg вернуть индекс начала контекста

//возврат: 0-не найден 1-найден >1-неоднозначность,несколько

//beg=true-контекст дб строго от начала

int DataCont::FindContext(const DataCont &ctx, int &idxbeg, bool beg) const

{

  int ret = 0;

  int sz1 = (int)Items.size();

  int sz2 = (int)ctx.Items.size();

  int i2 = 0;

  idxbeg = 0;

  if(sz2 < 1) return 1;

  for(int i1 = 0; i1 < sz1; ++i1) {

    if(Items[i1].shash == ctx.Items[i2].shash) {

      int ti1 = i1;

      for(;;) {

        if(++i2 >= sz2) {

          idxbeg = ti1;

          if(++ret > 1) return ret;

          if(beg) return ret;

          else break;

        }

        if(++i1 >= sz1) break;

        if(Items[i1].shash != ctx.Items[i2].shash) {

          if(beg) return ret;

          break;

        }

      }

      i1 = ti1;

      i2 = 0;

    }

    else if(beg) return ret;

  }

 

  return ret;

}

 

//---------------------------------------------------------------------------

//проверить корректность действия

bool Action::IsOk(void)

{

  if(dt1.Items.empty()) return false;

  if(act != 'I' && act != 'D' && act != 'R') return false;

  if(act == 'R' && dt2.Items.empty()) return false;

  return true;

}

 

//очистить действие

void Action::Clear(void)

{

  after.Items.clear();

  dt1.Items.clear();

  dt2.Items.clear();

  beg = false;

  act = 0;

}

 

//---------------------------------------------------------------------------

//записать последовательность действий a в свой контейнер комманд Items

void CmdCont::Actions2Cmd(const Actions &a)

{

  for(Actions::const_iterator it = a.begin(); it != a.end(); ++it) {

 

    cmd.sval = "AFTER";

    Items.push_back(cmd);

    if(it->beg) {

      cmd.sval = "BEGIN";

      Items.push_back(cmd);

    }

 

    if(it->after.Items.size() > 0)

      CopyVec(it->after);

 

    switch(it->act) {

      case 'D':

        cmd.sval = "DELETE";

        Items.push_back(cmd);

        CopyVec(it->dt1);

        break;

 

      case 'I':

        cmd.sval = "INSERT";

        Items.push_back(cmd);

        CopyVec(it->dt1);

        break;

 

      case 'R':

      default:

        cmd.sval = "REPLACE";

        Items.push_back(cmd);

        CopyVec(it->dt1);

        cmd.sval = "ON";

        Items.push_back(cmd);

        CopyVec(it->dt2);

        break;

    }

  }

}

 

//копировать строки из вектора StrExtItem в свой контейнер комманд Items

void CmdCont::CopyVec(const DataCont &vec)

{

  for(std::vector<StrExtItem>::const_iterator it = vec.Items.begin();

    it != vec.Items.end(); ++it) {

 

    cmd.sval = it->sval;

    Items.push_back(cmd);

  }

}

 

//---------------------------------------------------------------------------

//записать свой контейнер комманд Items в последовательность действий a

void CmdCont::Cmd2Actions(Actions &a)

{

  Action act;

  StrExtItem itm;

  enum mode {waitcmd, after, dt1, dt2} md = waitcmd;

  bool actrdn = false; //действие считано

 

  for(std::vector<StrItem>::const_iterator it = Items.begin();

    it != Items.end(); ++it) {

 

    switch(md) {

      default:

      case waitcmd:

        if(it->sval == "AFTER") {

          if(actrdn)

            if(act.IsOk()) a.push_back(act);

          actrdn = true;

          md = after;

          act.Clear();

        }

        break;

 

      case after:

        if(it->sval == "INSERT") { act.act = 'I'; md = dt1; }

        else if(it->sval == "DELETE") { act.act = 'D'; md = dt1; }

        else if(it->sval == "REPLACE") { act.act = 'R'; md = dt1; }

        else if(it->sval == "BEGIN") { act.beg = true; }

        else {

          itm.sval = it->sval;

          act.after.Items.push_back(itm);

        }

        break;

 

      case dt1:

        if(it->sval == "AFTER") {md = waitcmd; --it; }

        else if(act.act == 'R' && it->sval == "ON") {md = dt2; }

        else {

          itm.sval = it->sval;

          act.dt1.Items.push_back(itm);

        }

        break;

 

      case dt2:

        if(it->sval == "AFTER") {md = waitcmd; --it; }

        else {

          itm.sval = it->sval;

          act.dt2.Items.push_back(itm);

        }

        break;

    } //switch

  } //for

 

  if(actrdn)

    if(act.IsOk()) a.push_back(act);

}

 

//---------------------------------------------------------------------------

//класс-оболочка задачи

 

//сообщ об ошибках

const char* const NOERR = "";

const char* const NOTREAD = "Error reading file";

const char* const NOTWRITE = "Error writing file";

const char* const NOTFOUNDCTX = "Required context not found";

const char* const NOTAPPLAMB = "Change set applying is ambiguous";

 

Difr::Difr(void)

{

  errstr = NOERR;

}

 

Difr::~Difr(void)

{

 

}

 

const char* Difr::GetLastError(void)

{

  return errstr;

}

 

//---------------------------------------------------------------------------

//читать inp и out создать cmd

bool Difr::CreateCmd(const char* inpfn, const char* outfn, const char* cmdfn)

{

  inp.Items.clear();

  out.Items.clear();

  cmd.Items.clear();

 

  if(!inp.ReadItems(inpfn) || !out.ReadItems(outfn)) {

    errstr = NOTREAD;

    return false;

  }

 

  inp.CalcHashAll();

  out.CalcHashAll();

 

  Actions acts; //последовательность действий

  if(!CreateCmdProc(acts)) return false;

  cmd.Actions2Cmd(acts);

 

  if(!cmd.WriteItems(cmdfn)) {

    errstr = NOTWRITE;

    return false;

  }

 

  errstr = NOERR;

  return true;

}

 

//пройти по inp и out, созд действия, записать в контейнер a

bool Difr::CreateCmdProc(Actions &a)

{

  int szi = (int)inp.Items.size();

  int szo = (int)out.Items.size();

 

  int ii = 0, io = 0;

  int iframe, oframe;

  int found = 1;

  for( ; ii <= szi-1 && io <= szo-1; ++ii, ++io) { //проход по одинаковым

 

    if(inp.Items[ii].shash != out.Items[io].shash) { //разные

      iframe = ii;

      oframe = io;

      found = 0;

      int szctx = EXSIZECTX; //размер доп контекста

 

      for(;;) { //проход по inp

        for(;;) { //проход по out

          if(io >= szo) break;

 

          if(inp.Items[ii].shash == out.Items[io].shash) {

            //найдено, проверить контекст вниз

            ++found;

            int i = ii;

            int o = io;

            bool dif = false;

            for(int j = szctx; j > 0; --j) {

              ++i;

              ++o;

              if(i >= szi && o >= szo) break;

              if(i >= szi || o >= szo) { dif = true; break; }

              if(inp.Items[i].shash != out.Items[o].shash) { dif = true; break; }

              ++found;

            }

            if(dif) found = 0;

            if(found) break;

          }

          ++io;

        } //проход по out

 

        if(found) {

          //запись действия

          WriteAction(ii, io, iframe, oframe, a);

          break;

        }

 

        io = oframe;

        if(++ii >= szi) {

          //запись действия

          WriteAction(ii, io, iframe, oframe, a);

          break;

        }

      } //проход по inp

    } //разные

 

  } //проход по одинаковым

 

  //хвосты

  if(ii < szi) {

    //по inp

    if(found) iframe = ii;

    ii = szi;

    io = oframe = szo;

    WriteAction(ii, io, iframe, oframe, a);

  }

  else if(io < szo) {

    //по out

    if(found) oframe = io;

    io = szo;

    ii = iframe = szi;

    WriteAction(ii, io, iframe, oframe, a);

  }

 

  return true;

}

 

//записать действие в контейнер a

void Difr::WriteAction(int iix, int iox, int iframex, int oframex, Actions &a)

{

  Action act;

 

  if(iix > iframex && iox <= oframex) {

    //delete

    act.act = 'D';

    WriteContext(oframex, act);

    act.dt1.Items.insert(act.dt1.Items.begin(), &inp.Items[iframex], &inp.Items[iix-1]+1);

  }

  else if(iox > oframex && iix <= iframex) {

    //insert

    act.act = 'I';

    WriteContext(oframex, act);

    act.dt1.Items.insert(act.dt1.Items.begin(), &out.Items[oframex], &out.Items[iox-1]+1);

  }

  else {

    //replace

    act.act = 'R';

    WriteContext(oframex, act);

    act.dt1.Items.insert(act.dt1.Items.begin(), &inp.Items[iframex], &inp.Items[iix-1]+1);

    act.dt2.Items.insert(act.dt2.Items.begin(), &out.Items[oframex], &out.Items[iox-1]+1);

  }

 

  if(act.IsOk()) a.push_back(act);

}

 

//записать контекст действия act (в after)

//oframe-индекс после контекста

void Difr::WriteContext(int oframe, Action &act)

{

  int ctx = 0;

  DataCont tmp;

  int sizectx = 1; //размер контекста

  int i;

 

  if(oframe > 0) {

    for(;;) {

      //если контекст не уникальный-увеличивать вверх до начала

      if(oframe-sizectx >= 0) ctx = sizectx;

      else {

        ctx = oframe;

        act.beg = true;

      }

      tmp.Items.insert(tmp.Items.begin(), &out.Items[oframe-ctx], &out.Items[oframe]);

      if(act.beg) break;

      if(out.FindContext(tmp, i) < 2) break;

      ++sizectx;

      tmp.Items.clear();

    }

 

    act.after.Items = tmp.Items;

  }

  else act.beg = true;

}

 

//---------------------------------------------------------------------------

//читать inp и cmd создать out

bool Difr::ApplyCmd(const char* inpfn, const char* outfn, const char* cmdfn)

{

  inp.Items.clear();

  out.Items.clear();

  cmd.Items.clear();

 

  if(!inp.ReadItems(inpfn) || !cmd.ReadItems(cmdfn)) {

    errstr = NOTREAD;

    return false;

  }

 

  inp.CalcHashAll();

  out = inp;

 

  Actions acts;

  cmd.Cmd2Actions(acts);

  if(!ApplyCmdProc(acts)) return false;

 

  if(!out.WriteItems(outfn)) {

    errstr = NOTWRITE;

    return false;

  }

 

  errstr = NOERR;

  return true;

}

 

//применить действия из контейнера a к контейнеру строк out

bool Difr::ApplyCmdProc(Actions &a)

{

  int cts;

  int ibeg; //инд начала контекста

  int idx;  //инд операции

  DataCont tmp;

      std::vector<StrExtItem>::iterator itrve;

 

  for(Actions::iterator it = a.begin(); it != a.end(); ++it) {

 

    switch(it->act) {

      case 'I':

        it->after.CalcHashAll();

        it->dt1.CalcHashAll();

        cts = out.FindContext(it->after, ibeg, it->beg);

        if(cts < 1) { errstr = NOTFOUNDCTX; return false; }

        if(cts > 1) { errstr = NOTAPPLAMB; return false; }

        idx = ibeg + (int)it->after.Items.size();

                        itrve = out.Items.begin();

                        advance(itrve, idx);

        out.Items.insert(itrve, it->dt1.Items.begin(), it->dt1.Items.end());

        //out.Items.insert(&out.Items[idx], it->dt1.Items.begin(), it->dt1.Items.end());

        break;

 

      case 'D':

        tmp = it->dt1;

        tmp.Items.insert(tmp.Items.begin(), it->after.Items.begin(), it->after.Items.end());

        tmp.CalcHashAll();

        cts = out.FindContext(tmp, ibeg, it->beg);

        if(cts < 1) { errstr = NOTFOUNDCTX; return false; }

        if(cts > 1) { errstr = NOTAPPLAMB; return false; }

        idx = ibeg + (int)it->after.Items.size();

                        itrve = out.Items.begin();

                        advance(itrve, idx);

        out.Items.erase(itrve, itrve + it->dt1.Items.size());

        //out.Items.erase(&out.Items[idx], &out.Items[idx] + it->dt1.Items.size());

        break;

 

      case 'R':

        tmp = it->dt1;

        tmp.Items.insert(tmp.Items.begin(), it->after.Items.begin(), it->after.Items.end());

        tmp.CalcHashAll();

        it->dt2.CalcHashAll();

        cts = out.FindContext(tmp, ibeg, it->beg);

        if(cts < 1) { errstr = NOTFOUNDCTX; return false; }

        if(cts > 1) { errstr = NOTAPPLAMB; return false; }

        idx = ibeg + (int)it->after.Items.size();

                        itrve = out.Items.begin();

                        advance(itrve, idx);

        out.Items.erase(itrve, itrve + it->dt1.Items.size());

        //out.Items.erase(&out.Items[idx], &out.Items[idx] + it->dt1.Items.size());

                        itrve = out.Items.begin();

                        advance(itrve, idx);

        out.Items.insert(itrve, it->dt2.Items.begin(), it->dt2.Items.end());

        //out.Items.insert(&out.Items[idx], it->dt2.Items.begin(), it->dt2.Items.end());

        break;

 

      default:

        break;

    }

  }

  return true;

}

}; //namespace Difference

 

 

файл sccs.cpp

 

//---------------------------------------------------------------------------

// SCCS

// Обработка изменений в текстовых файлах

// (c) Vladimir Mishenin

// email: bobm@mail.ru

 

#include "stdafx.h"

#include "difr.h"

 

static void usage(void)

{

      std::cout << "Incorrect arguments." << std::endl;

      std::cout << "Usage:" << std::endl;

      std::cout << "sccs.exe source_file target_file changeset_file /apply" << std::endl;

}

 

int _tmain(int argc, _TCHAR* argv[])

{

      if(argc != 4 && argc != 5) {

            usage();

            return 1;

      }

      bool apply = false;

      if(argc == 5) {

            if(std::string(argv[4]) != std::string("/apply")) {

                  usage();

                  return 1;

            }

            apply = true;

      }

     

      Difference::Difr task;

 

      if(apply) {

            if(!task.ApplyCmd(argv[1], argv[2], argv[3])) {

                  std::cout << task.GetLastError() << std::endl;

                  return 1;

            }

      }

      else {

            if(!task.CreateCmd(argv[1], argv[2], argv[3])) {

                  std::cout << task.GetLastError() << std::endl;

                  return 1;

            }

      }

 

      std::cout << "Ok." << std::endl;

      return 0;

}

 

(c) Vladimir Mishenin