⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 extractcode.cpp

📁 Think in C++ 第二版源码
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//: C26:ExtractCode.cpp

// From Thinking in C++, 2nd Edition

// Available at http://www.BruceEckel.com

// (c) Bruce Eckel 1999

// Copyright notice in Copyright.txt

// Automatically extracts code files from

// ASCII text of this book.

#include <iostream>

#include <fstream>

#include <string>

#include <vector>

#include <map>

#include <set>

#include <algorithm>

using namespace std;



string copyright =

  "// From Thinking in C++, 2nd Edition\n"

  "// Available at http://www.BruceEckel.com\n"

  "// (c) Bruce Eckel 1999\n"

  "// Copyright notice in Copyright.txt\n";



string usage =

  " Usage:ExtractCode source\n"

  "where source is the ASCII file containing \n"

  "the embedded tagged sourcefiles. The ASCII \n"

  "file must also contain an embedded compiler\n"

  "configuration file called CompileDB.txt \n"

  "See Thinking in C++, 2nd ed. for details\n";



// Tool to remove the white space from both ends:

string trim(const string& s) {

  if(s.length() == 0)

    return s;

  int b = s.find_first_not_of(" \t");

  int e = s.find_last_not_of(" \t");

  if(b == -1) // No non-spaces

    return "";

  return string(s, b, e - b + 1);

}



// Manage all the error messaging:

void error(string problem, string message) {

  static const string border(

  "-----------------------------------------\n");

  class ErrReport {

    int count;

    string fname;

  public:

    ofstream errs;

    ErrReport(char* fn = "ExtractCodeErrors.txt") 

      : count(0),fname(fn),errs(fname.c_str()) {}

    void operator++(int) { count++; }

    ~ErrReport() {

      errs.close();

      // Dump error messages to console

      ifstream in(fname.c_str());

      cerr << in.rdbuf() << endl;

      cerr << count << " Errors found" << endl;

      cerr << "Messages in " << fname << endl;

    }

  };

  // Created on first call to this function;

  // Destructor reports total errors:

  static ErrReport report;

  report++;

  report.errs << border << message << endl

    << "Problem spot: " << problem << endl;

}



///// OS-specific code, hidden inside a class:

#ifdef __GNUC__  // For egcs under Linux/Unix

#include <unistd.h>

#include <sys/stat.h>

#include <stdlib.h>

class OSDirControl {

public:

  static string getCurrentDir() {

    char path[PATH_MAX];

    getcwd(path, PATH_MAX);

    return string(path);

  }

  static void makeDir(string dir) {

    mkdir(dir.c_str(), 0777);

  }

  static void changeDir(string dir) {

    chdir(dir.c_str());

  }

};

#else // For Dos/Windows:

#include <direct.h>

class OSDirControl {

public:

  static string getCurrentDir() {

    char path[_MAX_PATH];

    getcwd(path, _MAX_PATH);

    return string(path);

  }

  static void makeDir(string dir) {

    mkdir(dir.c_str());

  }

  static void changeDir(string dir) {

    chdir(dir.c_str());

  }

};

#endif ///// End of OS-specific code



class PushDirectory {

  string oldpath;

public:

  PushDirectory(string path);

  ~PushDirectory() {

    OSDirControl::changeDir(oldpath);

  }

  void pushOneDir(string dir) {

    OSDirControl::makeDir(dir);

    OSDirControl::changeDir(dir);

  }

};



PushDirectory::PushDirectory(string path) {

  oldpath = OSDirControl::getCurrentDir();

  while(path.length() != 0) {

    int colon = path.find(':');

    if(colon != string::npos) {

      pushOneDir(path.substr(0, colon));

      path = path.substr(colon + 1);

    } else {

      pushOneDir(path);

      return;

    }

  }

}



//--------------- Manage code files -------------

// A CodeFile object knows everything about a

// particular code file, including contents, path

// information, how to compile, link, and test 

// it, and which compilers it won't compile with.

enum TType {header, object, executable, none};



class CodeFile {

  TType _targetType;

  string _rawName, // Original name from input

    _path, // Where the source file lives

    _file, // Name of the source file

    _base, // Name without extension

    _tname, // Target name

    _testArgs; // Command-line arguments

  vector<string>

    lines, // Contains the file

    _compile, // Compile dependencies

    _link; // How to link the executable

  set<string>

    _noBuild; // Compilers it won't compile with

  bool writeTags; // Whether to write the markers

  // Initial makefile processing for the file:

  void target(const string& s);

  // For quoted #include headers:

  void headerLine(const string& s);

  // For special dependency tag marks:

  void dependLine(const string& s);

public:

  CodeFile(istream& in, string& s);

  const string& rawName() { return _rawName; }

  const string& path() { return _path; }

  const string& file() { return _file; }

  const string& base() { return _base; }

  const string& targetName() { return _tname; }

  TType targetType() { return _targetType; }

  const vector<string>& compile() {

    return _compile;

  }

  const vector<string>& link() {

    return _link;

  }

  const set<string>& noBuild() {

    return _noBuild;

  }

  const string& testArgs() { return _testArgs; }

  // Add a compiler it won't compile with:

  void addFailure(const string& failure) {

    _noBuild.insert(failure);

  }

  bool compilesOK(string compiler) {

    return _noBuild.count(compiler) == 0;

  }

  friend ostream&

  operator<<(ostream& os, const CodeFile& cf) {

    copy(cf.lines.begin(), cf.lines.end(),

      ostream_iterator<string>(os, ""));

    return os;

  }

  void write() {

    PushDirectory pd(_path);

    ofstream listing(_file.c_str());

    listing << *this;  // Write the file

  }

  void dumpInfo(ostream& os);

};



void CodeFile::target(const string& s) {

  // Find the base name of the file (without

  // the extension):

  int lastDot = _file.find_last_of('.');

  if(lastDot == string::npos) {

    error(s, "Missing extension");

    exit(1);

  }

  _base = _file.substr(0, lastDot);

  // Determine the type of file and target:

  if(s.find(".h") != string::npos ||

     s.find(".H") != string::npos) {

    _targetType = header;

    _tname = _file;

    return;

  }

  if(s.find(".txt") != string::npos

      || s.find(".TXT") != string::npos

      || s.find(".dat") != string::npos

      || s.find(".DAT") != string::npos) {

    // Text file, not involved in make

    _targetType = none;

    _tname = _file;

    return;

  }

  // C++ objs/exes depend on their own source:

  _compile.push_back(_file);

  if(s.find("{O}") != string::npos) {

    // Don't build an executable from this file

    _targetType = object;

    _tname = _base;

  } else {

    _targetType = executable;

    _tname = _base;

    // The exe depends on its own object file:

    _link.push_back(_base);

  }

}



void CodeFile::headerLine(const string& s) {

  int start = s.find('\"');

  int end = s.find('\"', start + 1);

  int len = end - start - 1;

  _compile.push_back(s.substr(start + 1, len));

}



void CodeFile::dependLine(const string& s) {

  const string linktag("//{L} ");

  string deps = trim(s.substr(linktag.length()));

  while(true) {

    int end = deps.find(' ');

    string dep = deps.substr(0, end);

    _link.push_back(dep);

    if(end == string::npos) // Last one

      break;

    else

      deps = trim(deps.substr(end));

  }

}



CodeFile::CodeFile(istream& in, string& s) {

  // If false, don't write begin & end tags:

  writeTags = (s[3] != '!');

  // Assume a space after the starting tag:

  _file = s.substr(s.find(' ') + 1);

  // There will always be at least one colon:

  int lastColon = _file.find_last_of(':');

  if(lastColon == string::npos) {

    error(s, "Missing path");

    lastColon = 0; // Recover from error

  }

  _rawName = trim(_file);

  _path = _file.substr(0, lastColon);

  _file = _file.substr(lastColon + 1);

  _file =_file.substr(0,_file.find_last_of(' '));

  cout << "path = [" << _path << "] "

    << "file = [" << _file << "]" << endl;

  target(s); // Determine target type

  if(writeTags){

    lines.push_back(s + '\n');

    lines.push_back(copyright);

  }

  string s2;

  while(getline(in, s2)) {

    // Look for specified link dependencies:

    if(s2.find("//{L}") == 0) // 0: Start of line

      dependLine(s2);

    // Look for command-line arguments for test:

    if(s2.find("//{T}") == 0) // 0: Start of line

      _testArgs = s2.substr(strlen("//{T}") + 1);

    // Look for quoted includes:

    if(s2.find("#include \"") != string::npos) {

      headerLine(s2); // Grab makefile info

    }

    // Look for end marker:

    if(s2.find("//" "/:~") != string::npos) {

      if(writeTags)

        lines.push_back(s2 + '\n');

      return;  // Found the end

    }

    // Make sure you don't see another start:

    if(s2.find("//" ":") != string::npos

       || s2.find("/*" ":") != string::npos) {

      error(s, "Error: new file started before"

        " previous file concluded");

      return;

    }

    // Write ordinary line:

    lines.push_back(s2 + '\n');

  }

}



void CodeFile::dumpInfo(ostream& os) {

  os << _path << ':' << _file << endl;

  os << "target: " << _tname << endl;

  os << "compile: " << endl;

  for(int i = 0; i < _compile.size(); i++)

    os << '\t' << _compile[i] << endl;

  os << "link: " << endl;

  for(int i = 0; i < _link.size(); i++)

    os << '\t' << _link[i] << endl;

  if(_noBuild.size() != 0) {

    os << "Won't build with: " << endl;

    copy(_noBuild.begin(), _noBuild.end(),

      ostream_iterator<string>(os, "\n"));

  }

}



//--------- Manage compiler information ---------

class CompilerData {

  // Information about each compiler:

  vector<string> rules; // Makefile rules

  set<string> fails; // Non-compiling files

  string objExtension; // File name extensions

  string exeExtension;

  // For OS-specific activities:

  bool _dos, _unix;

  // Store the information for all the compilers:

  static map<string, CompilerData> compilerInfo;

  static set<string> _compilerNames;

public:

  CompilerData() : _dos(false), _unix(false) {}

  // Read database of various compiler's 

  // information and failure listings for 

  // compiling the book files:

  static void readDB(istream& in);

  // For enumerating all the compiler names:

  static set<string>& compilerNames() {

    return _compilerNames;

  }

  // Tell this CodeFile which compilers

  // don't work with it:

  static void addFailures(CodeFile& cf);

  // Produce the proper object file name

  // extension for this compiler:

  static string obj(string compiler);

  // Produce the proper executable file name

  // extension for this compiler:

  static string exe(string compiler);

  // For inserting a particular compiler's

  // rules into a makefile:

  static void 

  writeRules(string compiler, ostream& os);

  // Change forward slashes to backward 

  // slashes if necessary:

  static string 

  adjustPath(string compiler, string path);

  // So you can ask if it's a Unix compiler:

  static bool isUnix(string compiler) {

    return compilerInfo[compiler]._unix;

  }

  // So you can ask if it's a dos compiler:

  static bool isDos(string compiler) {

    return compilerInfo[compiler]._dos;

  }

  // Display information (for debugging):

  static void dump(ostream& os = cout);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -