//: C03:ExtractCode.cpp {-edg} {RunByHand}
// Z knihy "Myslíme v jazyce C++, část 2" od Bruce Eckela a Chucka Allisona.
// (c) 1995-2004 MindView, Inc. Všechna práva vyhrazena.
// Přečtěte si podmínky používání zdrojových kódů umístěné v souboru 
// 'Licence.txt' dodávaném spolu s balíčkem kódu dostupným na www.MindView.net.
// Vyčlenit kód z textu.
#include <cassert>
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
using namespace std;

// Zděděné nestandardní halvičkové soubory C kvůli mkdir()
#if defined(__GNUC__) || defined(__MWERKS__)
#include <sys/stat.h>
#elif defined(__BORLANDC__) || defined(_MSC_VER) \
  || defined(__DMC__)
#include <direct.h>
#else
#error Překladač není podporován
#endif

// Zjistit, zda adresář existuje 
// tím, že e v něm pokusíme vytvořit
// nový výstupní soubor.
bool exists(string fname) {
  size_t len = fname.length();
  if(fname[len-1] != '/' && fname[len-1] != '\\')
    fname.append("/");
  fname.append("000.tmp");
  ofstream outf(fname.c_str());
  bool existFlag = outf;
  if(outf) {
    outf.close();
    remove(fname.c_str());
  }
  return existFlag;
}

int main(int argc, char* argv[]) {
  // Zjistit, zda je k dispozici název vstupního souboru
  if(argc == 1) {
    cerr << "Použití: extractCode soubor [adr]" << endl;
    exit(EXIT_FAILURE);
  }
  // Zjistit, zda soubor existuje
  ifstream inf(argv[1]);
  if(!inf) {
    cerr << "chyba při otevírání souboru: " << argv[1] << endl;
    exit(EXIT_FAILURE);
  }
  // Zjistit výstupní adresář
  string root("./");  // aktuální je výchozí
  if(argc == 3) {
    // Zjistit, zda existuje výstupní adresář
    root = argv[2];
    if(!exists(root)) {
      cerr << "Takový adresář neexistuje: " << root << endl;
      exit(EXIT_FAILURE);
    }
    size_t rootLen = root.length();
    if(root[rootLen-1] != '/' && root[rootLen-1] != '\\')
      root.append("/");
  }
  // Číst vstupní soubor po řádcích 
	// a kontrolovat oddělovače kódu
  string line;
  bool inCode = false;
  bool printDelims = true;
  ofstream outf;
  while(getline(inf, line)) {
    size_t findDelim = line.find("//" "/:~");
    if(findDelim != string::npos) {
      // Vydat poslední řádek a zavřít soubor
      if(!inCode) {
        cerr << "Špatné řádky" << endl;
        exit(EXIT_FAILURE);
      }
      assert(outf);
      if(printDelims)
        outf << line << endl;
      outf.close();
      inCode = false;
      printDelims = true;
    } else {
      findDelim = line.find("//" ":");
      if(findDelim == 0) {
        // Zkontrolovat direktivu '!'
        if(line[3] == '!') {
          printDelims = false;
          ++findDelim;  // Pro další hledání přeskočit '!'
        }
        // zjistit název podadresáře, pokud je k dispozici
        size_t startOfSubdir =
          line.find_first_not_of(" \t", findDelim+3);
        findDelim = line.find(':', startOfSubdir);
        if(findDelim == string::npos) {
          cerr << "chybí jméno souboru\n" << endl;
          exit(EXIT_FAILURE);
        }
        string subdir;
        if(findDelim > startOfSubdir)
          subdir = line.substr(startOfSubdir,
                               findDelim - startOfSubdir);
        // Zjistit jméno souboru (mělo by být jedno!)
        size_t startOfFile = findDelim + 1;
        size_t endOfFile =
          line.find_first_of(" \t", startOfFile);
        if(endOfFile == startOfFile) {
          cerr << "chybí jméno souboru" << endl;
          exit(EXIT_FAILURE);
        }
        // Máme všechny části; sestavit název celé cesty
        string fullPath(root);
        if(subdir.length() > 0)
          fullPath.append(subdir).append("/");
        assert(fullPath[fullPath.length()-1] == '/');
        if(!exists(fullPath))
#if defined(__GNUC__) || defined(__MWERKS__)
          mkdir(fullPath.c_str(), 0);  // Vytvořit podadresář
#else
          mkdir(fullPath.c_str());  // Create subdir
#endif
        fullPath.append(line.substr(startOfFile,
                        endOfFile - startOfFile));
        outf.open(fullPath.c_str());
        if(!outf) {
          cerr << "chyba při otevření " << fullPath
               << " pro výstup" << endl;
          exit(EXIT_FAILURE);
        }
        inCode = true;
        cout << "Zpracovávání " << fullPath << endl;
        if(printDelims)
          outf << line << endl;
      }
      else if(inCode) {
        assert(outf);
        outf << line << endl;  // vydat střední řádek kódu
      }
    }
  }
  exit(EXIT_SUCCESS);
} ///:~
