1 // =================================
  2 // Copyright (c) 2020 Seppo Laakko
  3 // Distributed under the MIT license
  4 // =================================
  5 
  6 #include <iostream>
  7 #include <stdexcept>
  8 #include <soulng/util/Path.hpp>
  9 #include <soulng/util/TextUtils.hpp>
 10 #include <soulng/util/InitDone.hpp>
 11 #include <sngxml/xpath/InitDone.hpp>
 12 #include <sngcpp/pp/InitDone.hpp>
 13 #include <sngcpp/ast/InitDone.hpp>
 14 #include <gendoc/gendoc/Project.hpp>
 15 #include <gendoc/html/Html.hpp>
 16 
 17 using namespace soulng::util;
 18 
 19 const char* Version()
 20 {
 21     return "1.0.0";
 22 }
 23 
 24 void PrintUsage()
 25 {
 26     std::cout << "gendoc version " << Version() << std::endl;
 27     std::cout << "Reverse engineering tool for Windows x64." << std::endl;
 28     std::cout << "Usage: gendoc [options] [[PATH\\]gendoc.xml]" << std::endl;
 29     std::cout << "Generate HTML content for a Visual C++ project defined in the gendoc.xml." << std::endl;
 30     std::cout << "If no gendoc.xml parameter is given, assumes that the current working directory contains gendoc.xml." << std::endl;
 31     std::cout << "Options:" << std::endl;
 32     std::cout << "--help | -h" << std::endl;
 33     std::cout << "  Print help and exit." << std::endl;
 34     std::cout << "--verbose | -v" << std::endl;
 35     std::cout << "  Be verbose." << std::endl;
 36     std::cout << "--rebuild | -r" << std::endl;
 37     std::cout << "  Rebuild everything." << std::endl;
 38     std::cout << "--clean | -l" << std::endl;
 39     std::cout << "  Clean everything." << std::endl;
 40     std::cout << "--ast | -a" << std::endl;
 41     std::cout << "  Generate just ASTs." << std::endl;
 42     std::cout << "--content | -c" << std::endl;
 43     std::cout << "  Generate content when ASTS are already generated." << std::endl;
 44     std::cout << "--end-message | -e" << std::endl;
 45     std::cout << "  Generate status.msg in the same directory (used when executed recursively from the parent directory)." << std::endl;
 46     std::cout << "--single-process | -s" << std::endl;
 47     std::cout << "  Run in single process." << std::endl;
 48 }
 49 
 50 struct Initializer 
 51 {
 52     Initializer()
 53     {
 54         soulng::util::Init();
 55         sngxml::xpath::Init();
 56         sngcpp::pp::Init();
 57         sngcpp::ast::Init();
 58         gendoc::html::InitHeaderElementNames();
 59     }
 60     ~Initializer()
 61     {
 62         sngcpp::ast::Done();
 63         sngcpp::pp::Done();
 64         sngxml::xpath::Done();
 65         soulng::util::Done();
 66     }
 67 };
 68 
 69 int main(int argcconst char** argv)
 70 {
 71     Initializer initializer;
 72     try
 73     {
 74         bool verbose = false;
 75         bool rebuild = false;
 76         bool clean = false;
 77         bool ast = false;
 78         bool content = false;
 79         bool endMessage = false;
 80         bool single = false;
 81         std::vector<std::string> docFilePaths;
 82         for (int i = 1; i < argc; ++i)
 83         {
 84             std::string arg = argv[i];
 85             if (StartsWith(arg"--"))
 86             {
 87                 if (arg == "--help")
 88                 {
 89                     PrintUsage();
 90                     return 1;
 91                 }
 92                 else if (arg == "--verbose")
 93                 {
 94                     verbose = true;
 95                 }
 96                 else if (arg == "--rebuild")
 97                 {
 98                     rebuild = true;
 99                 }
100                 else if (arg == "--clean")
101                 {
102                     clean = true;
103                 }
104                 else if (arg == "--ast")
105                 {
106                     ast = true;
107                 }
108                 else if (arg == "--content")
109                 {
110                     content = true;
111                 }
112                 else if (arg == "--end-message")
113                 {
114                     endMessage = true;
115                 }
116                 else if (arg == "--single-process")
117                 {
118                     single = true;
119                 }
120                 else
121                 {
122                     throw std::runtime_error("unknown option '" + arg + "'");
123                 }
124             }
125             else if (StartsWith(arg"-"))
126             {
127                 std::string options = arg.substr(1);
128                 if (options.empty())
129                 {
130                     throw std::runtime_error("unknown option '" + arg + "'");
131                 }
132                 for (char o : options)
133                 {
134                     if (o == 'h')
135                     {
136                         PrintUsage();
137                         return 1;
138                     }
139                     else if (o == 'v')
140                     {
141                         verbose = true;
142                     }
143                     else if (o == 'r')
144                     {
145                         rebuild = true;
146                     }
147                     else if (o == 'l')
148                     {
149                         clean = true;
150                     }
151                     else if (o == 'a')
152                     {
153                         ast = true;
154                     }
155                     else if (o == 'c')
156                     {
157                         content = true;
158                     }
159                     else if (o == 'e')
160                     {
161                         endMessage = true;
162                     }
163                     else if (o == 's')
164                     {
165                         single = true;
166                     }
167                     else
168                     {
169                         throw std::runtime_error("unknown option '-" + std::string(1o) + "'");
170                     }
171                 }
172             }
173             else
174             {
175                 docFilePaths.push_back(GetFullPath(arg));
176             }
177         }
178         if (docFilePaths.empty())
179         {
180             std::string docFilePath = GetFullPath(Path::Combine(GetCurrentWorkingDirectory()"gendoc.xml"));
181             docFilePaths.push_back(docFilePath);
182         }
183         for (const std::string& docFilePath : docFilePaths)
184         {
185             if (verbose && !ast && !content)
186             {
187                 std::cout << "> " << docFilePath << std::endl;
188             }
189             gendoc::Project project(docFilePath);
190             if (clean)
191             {
192                 project.Clean(verbosesingle);
193             }
194             else if (ast)
195             {
196                 project.GenerateAst(verboserebuildfalse);
197             }
198             else if (content)
199             {
200                 project.GenerateContent(verboserebuildendMessagesingle);
201             }
202             else
203             {
204                 project.Process(verboserebuildsingle);
205             }
206         }
207     }
208     catch (const std::exception& ex;)
209     {
210         std::cerr << ex.what() << std::endl;
211         return 1;
212     }
213     return 0;
214 }