Advertisement
WeltEnSTurm

Untitled

May 5th, 2018
366
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 13.83 KB | None | 0 0
  1.  
  2. #include <stdlib.h>
  3.  
  4. #include <string>
  5. #include <vector>
  6. #include <functional>
  7. #include <fstream>
  8. #include <map>
  9. #include <list>
  10.  
  11. #include "ws/tools/app.hpp"
  12. #include "ws/base.hpp"
  13. #include "ws/exception.hpp"
  14. #include "ws/data/decoder.hpp"
  15. #include "ws/io.hpp"
  16. #include "ws/sys/process.hpp"
  17. #include "ws/sys/time.hpp"
  18. #include "ws/sys/console.hpp"
  19. #include "ws/list.hpp"
  20. #include "ws/path.hpp"
  21.  
  22. char toLower(char in){
  23.   if(in<='Z' && in>='A')
  24.     return in-('Z'-'z');
  25.   return in;
  26. }
  27.  
  28. namespace ws {
  29.     using namespace std;
  30.  
  31.     class pibuilder {
  32.         public:
  33.  
  34.             struct source {
  35.                 string path;
  36.                 string actualPath;
  37.             };
  38.  
  39.             string basePath;
  40.             string filePath;
  41.  
  42.             string compiler = "g++ -std=gnu++11 -O3 -Wall -c -fmessage-length=0 ";
  43.             string linker = "g++ ";
  44.             string output = "bin/program.exe";
  45.             string buildPath =
  46. #if osWindows
  47.                     "build/windows";
  48. #elif osLinux
  49.                     "build/linux";
  50. #endif
  51.             string vipath;
  52.             bool debug = false;
  53.  
  54.             list<string> includePaths;
  55.             string libraryPaths;
  56.             string libraries;
  57.  
  58.             list<source> sourceFiles;
  59.             list<string> objStack;
  60.             list<string> smartLibs;
  61.             list<string> processedSmartlibs;
  62.             list<string> runPostbuild;
  63.             struct SBool {
  64.                 bool b = false;
  65.                 operator bool(){return b;}
  66.                 void operator=(bool _b){b=_b;}
  67.             };
  68.             map<string,SBool> includesParsed;
  69.  
  70.             path::time oldestObj;
  71.  
  72.             string objects;
  73.  
  74.             list<string> IgnoreList;
  75.  
  76.         public:
  77.  
  78.             pibuilder(const string& f){
  79.                 string file = f;
  80.                 std::cout << console::white;
  81.                 Exception::displayFile = false;
  82.  
  83.                 for(char& c: file)
  84.                     if(c == '\\') c = '/';
  85.  
  86.                 if(file.find(".pi") >= file.size())
  87.                     file = findPi(file.substr(0, file.find_last_of('/')));
  88.  
  89.                 if(!file.size()) throw Exception("no project file found: \"%\"", f);
  90.  
  91.                 if(file.find("/") < file.size()){
  92.                     basePath = file.substr(0, file.find_last_of("/")+1);
  93.                     filePath = file.substr(file.find_last_of('/')+1, file.size()-file.find_last_of('/')-1);
  94.                 } else {
  95.                     basePath = "";
  96.                     filePath = file;
  97.                 }
  98.  
  99.                 if(basePath.size()){
  100.                     chdir(basePath.c_str());
  101.                 }
  102.  
  103.                 objStack.push_back("");
  104.  
  105.                 decodeFile();
  106.             }
  107.  
  108.             string findPi(string s){
  109.                 while(path::isFolder(s)){
  110.                     for(string f: path::list(s)){
  111.                         if(f.find_last_of('.') < f.size() and f.substr(f.find_last_of('.'), f.size()-f.find_last_of('.')) == ".pi")
  112.                             return s + '/' + f;
  113.                     }
  114.                     if(s.find_last_of('/') < s.size())
  115.                         s = s.substr(0, s.find_last_of('/'));
  116.                     else break;
  117.                 }
  118.                 return "";
  119.             }
  120.  
  121.             void decodeFile(){
  122.                 std::function<void(const string&,const string&,bool)> callback = [&](const string& cmd, const string& content, bool block){
  123.  
  124.                     if(debug)
  125.                         io::writeln("%: [%][%]", block ? "block" : "var", cmd, content);
  126.                     if(cmd == "linux")
  127. #if osLinux
  128.                         decode::text(content, callback)
  129. #endif
  130.                     ;else if(cmd == "windows")
  131. #if osWindows
  132.                         decode::text(content, callback)
  133. #endif
  134.                     ;else if(cmd == "compiler")
  135.                         compiler = content + " ";
  136.  
  137.                     else if(cmd == "linker")
  138.                         linker = content + " ";
  139.  
  140.                     else if(cmd == "output"){
  141.                         output = content
  142. #if osWindows
  143.                                 + ".exe"
  144. #endif
  145.                         ;
  146.                         uint cur = 0;
  147.                         while(true){
  148.                             cur = content.find('/', cur+1);
  149.                             if(cur >= content.size()) break;
  150.                             string dir = content.substr(0, cur);
  151.                             path::create(dir);
  152.                         }
  153.                     }
  154.  
  155.                     else if(cmd == "vipath"){
  156.                         vipath = content;
  157.                     }
  158.  
  159.                     else if(cmd == "buildpath" || cmd == "objs"){
  160.                         buildPath = content +
  161. #if osWindows
  162.                                 "/windows"
  163. #elif osLinux
  164.                                 "/linux"
  165. #endif
  166.                                 ;
  167.                     }
  168.  
  169.                     else if(cmd == "source"){
  170.                         if(block){
  171.                             decode::text(content, [&](const string& c, const string& cnt, bool block){
  172.                                 if(c == "path"){
  173.                                     addSourcePath(cnt);
  174.                                 }
  175.                             });
  176.                         }else{
  177.                             addSourcePath(content);
  178.                         }
  179.                     }
  180.                     else if(cmd == "include"){
  181.                         if(block){
  182.                             decode::text(content, [&](const string& c, const string& cnt, bool block){
  183.                                 if(c == "path"){
  184.                                     if(!path::isFolder(basePath + cnt))
  185.                                         throw Exception("Couldn't find include directory \"" + cnt + "\"");
  186.                                     includePaths.push_back(basePath + cnt);
  187.                                 }
  188.                             });
  189.                         }else{
  190.                             if(!path::isFolder(content))
  191.                                 throw Exception("Couldn't find include directory \"" + content + "\"");
  192.                             includePaths.push_back(content);
  193.                         }
  194.                     }
  195.                     else if(cmd == "library"){
  196.                         if(block){
  197.                             decode::text(content, [&](const string& c, const string& cnt, bool block){
  198.                                 if(c == "lib"){
  199.                                     libraries = " -l\"" + cnt + "\"" + libraries;
  200.                                 }else if(c == "path"){
  201.                                     if(!path::isFolder(basePath + cnt))
  202.                                             throw Exception("Couldn't find library directory \"" + cnt + "\"");
  203.                                     libraryPaths += " -L\"" + basePath + cnt + "\"";
  204.                                 }
  205.                             });
  206.                         }else{
  207.                             libraries = " -l\"" + content + "\"" + libraries;
  208.                         }
  209.                     }
  210.                     else if(cmd == "smartlib"){
  211.                         if(block){
  212.                             decode::text(content, [&](const string& c, const string& cnt, bool block){
  213.                                 if(c == "path"){
  214.                                     if(!path::isFolder(basePath + cnt))
  215.                                         throw Exception("Couldn't find smartlib directory \"" + cnt + "\"");
  216.                                     smartLibs.push_back(basePath + cnt);
  217.                                     includePaths.push_back(basePath + cnt);
  218.                                 }
  219.                             });
  220.                         } else {
  221.                             if(!path::isFolder(basePath + content))
  222.                                 throw Exception("Couldn't find smartlib directory \"" + content + "\"");
  223.                             smartLibs.push_back(basePath + content);
  224.                             includePaths.push_back(basePath + content);
  225.                         }
  226.                     }
  227.                     else if(cmd == "debug"){
  228.                         if(content == "on")
  229.                             debug = true;
  230.                         else
  231.                             debug = false;
  232.                     }
  233.                     else if(cmd == "run" || cmd == "do"){
  234.                         if(content == "output")
  235.                             runPostbuild.push_back(output);
  236.                         else
  237.                             runPostbuild.push_back(content);
  238.                     }
  239.                     else {
  240.                         io::writeln("Unknown option: " + cmd);
  241.                     }
  242.                 };
  243.  
  244.                 decode::file(basePath + filePath, callback);
  245.             }
  246.  
  247.             void Clean(){
  248.                 path::remove(basePath + buildPath);
  249.                 io::writeln("deleted \"%\"", basePath + buildPath);
  250.             }
  251.  
  252.             bool Compile(){
  253.                 bool newObject = !path::isFile(basePath + output);
  254.                 for(source& s: sourceFiles){
  255.                     includesParsed.clear();
  256.                     string obj;
  257.                     try {
  258.                         processSource(s.actualPath, 1, s.path);
  259.                         obj = getObjectPath(s.path);
  260.                         objects += " \"" + obj + "\"";
  261.                         if(!checkActuality(s, obj)) continue;
  262.                     } catch(Exception& e) {
  263.                         throw Exception(e, "error while parsing \"" + s.path + "\"");
  264.                     }
  265.                     io::writeln("compiling %% [% includes]", vipath.size() ? vipath + '/' : "", s.path, includesParsed.size());
  266.                     io::write(console::yellow);
  267.                     path::create(obj);
  268.                     string incl;
  269.                     for(string& i: includePaths)
  270.                         incl += " -I\"" + i + "\"";
  271.                     if(TryProgram(compiler + incl + " -o \"" + obj + "\" \"" + s.actualPath + "\""))
  272.                         throw Exception("compiler error");
  273.                     io::write(console::white);
  274.                     newObject = true;
  275.                 }
  276.                 return newObject;
  277.             }
  278.  
  279.             void Link(){
  280.                 io::writeln("linking \"%\"", output);
  281.                 std::cout << console::yellow;
  282.                 if(TryProgram(linker + "-o" + "\"" + basePath + output + "\"" + libraryPaths + objects + libraries))
  283.                     throw Exception("failed to link");
  284.                 std::cout << console::white;
  285.             }
  286.  
  287.             string getObjectPath(string p){
  288.                 while(p.find("../") < p.size())
  289.                     p.erase(0, 3);
  290.                 if(p.find('.') < p.size())
  291.                     p = basePath + buildPath + '/' + p.substr(0, p.find_last_of('.')) + ".o";
  292.                 else
  293.                     throw Exception("\"" + p + "\" has no file extension");
  294.                 return p;
  295.             }
  296.  
  297.             void RunPost(){
  298.                 for(string& s: runPostbuild)
  299.                     if(s == "pause") std::cin.get();
  300.                     else if(sys::process(basePath + s))
  301.                         throw Exception("Failed to run \"" + s + "\"");
  302.             }
  303.  
  304.             list<string> parseIncludes(const string& path, bool all = false){
  305.                 if(!path::isFile(path)) return {};
  306.                 list<string> files;
  307.                 ifstream f(path);
  308.                 string block;
  309.                 while(f.good()){
  310.                     string buffer;
  311.                     std::getline(f, buffer);
  312.                     while(buffer.find('\r') < buffer.size())
  313.                         buffer.erase(buffer.find('\r'),1);
  314.                     block += buffer + '\n';
  315.  
  316.                     if(block.find("/*") < block.size()){
  317.                         uint start = block.find("/*");
  318.                         uint end = block.find("*/", start)+2;
  319.                         if(end < block.size()){
  320.                             block.erase(start, end-start);
  321.                         } else
  322.                             continue;
  323.                     }
  324.  
  325.                     if(block.find("//") < block.size()){
  326.                         uint start = block.find("//");
  327.                         uint end = block.find("\n", start)+1;
  328.                         if(end < block.size()){
  329.                             block.erase(start, end-start);
  330.                         } else
  331.                             continue;
  332.                     }
  333.  
  334.                     if(block.find("#include") < block.size()){
  335.                         for(ulong i=block.find("#include")+8; i<block.size(); i++){
  336.                             uint start = 0;
  337.                             uint end = 0;
  338.                             if(block[i] == ' ' || block[i] == '\t') continue;
  339.                             if(block[i] != '\"' && (!all || block[i] != '<')) break;
  340.                             start = i;
  341.                             end = block.find_first_of('\"', start+1);
  342.                             if(!start || end >= block.size()) break;
  343.                             string result = block.substr(start+1, end-start-1);
  344. #if osWindows
  345.                                 for(size_t i=0; i<result.size(); i++)
  346.                                     result[i] = toLower(result[i]);
  347. #endif
  348.                             if(!includesParsed[result]){
  349.                                 includesParsed[result] = true;
  350.                             }
  351.                             files.push_back(result);
  352.                             break;
  353.                         }
  354.                     }
  355.                     block.erase();
  356.                 }
  357.                 return files;
  358.             }
  359.  
  360.             void processSource(const string& s, long level = 0, string nicePath = ""){
  361.                 if(find(processedSmartlibs, s) >= 0) return;
  362.                 processedSmartlibs.push_back(s);
  363.  
  364.                 if(s.find(".h") < s.size() && findFile(s.substr(0, s.find_last_of('.'))+".cpp").size()){
  365.                     string srcPath = findFile(s.substr(0, s.find_last_of('.'))+".cpp");
  366.                     source src = { srcPath, srcPath };
  367.                     if(nicePath.size())
  368.                         src.path = nicePath.substr(0, nicePath.find_last_of('.')) + string(".cpp");
  369.                     bool already = false;
  370.                     for(source f: sourceFiles)
  371.                         if(f.actualPath == srcPath)
  372.                             already = true;
  373.                     if(!already)
  374.                         sourceFiles.push_back(src);
  375.                 }
  376.  
  377.  
  378.                 for(string i: parseIncludes(s)){
  379.                     bool found = false;
  380.                     for(string& l: includePaths){
  381.                         string src;
  382.                         if(path::isFile(l + '/' + i))
  383.                             src = l + '/' + i;
  384.                         else if(path::isFile(s.substr(0, s.find_last_of('/')+1) + i))
  385.                             src = s.substr(0, s.find_last_of('/')+1) + i;
  386.                         else
  387.                             continue;
  388.                         found = true;
  389.  
  390.                         try {
  391.                             processSource(src, level + 1, i);
  392.                         } catch(Exception& e) {
  393.                             throw Exception(e, "error while parsing \"" + i + "\"");
  394.                         }
  395.                         break;
  396.                     }
  397.                     if(!found)
  398.                         throw Exception("failed to find \"" + i + "\"");
  399.  
  400.                 }
  401.             }
  402.  
  403.             bool checkActuality(const source& s, const string& obj, long level = 0){
  404.  
  405.                 if(!path::isFile(s.actualPath)) throw Exception("could not find \"" + s.path + "\"");
  406.                 if(!path::isFile(obj)) return true;
  407.                 if(path::time(s.actualPath) >= path::time(obj)) return true;
  408.  
  409.                 if(debug){
  410.                     for(long i=0; i<=level; i++)
  411.                         io::write("  ");
  412.                     io::writeln(s.path);
  413.                 }
  414.  
  415.                 for(string file: parseIncludes(s.actualPath)){
  416.                     try {
  417.                         if(findFile(file).size()){
  418.                             if(checkActuality({file, findFile(file)}, obj, level + 1))
  419.                                 return true;
  420.                         } else {
  421.                             if(findFile(s.actualPath.substr(0, s.actualPath.find_last_of('/')+1) + file).size()){
  422.                                 if(checkActuality({file, findFile(s.actualPath.substr(0, s.actualPath.find_last_of('/')+1) + file)}, obj, level + 1))
  423.                                     return true;
  424.                             } else {
  425.                                 throw Exception("could not find \"" + file + "\"");
  426.                             }
  427.                         }
  428.                     } catch(Exception& e) {
  429.                         throw Exception(e, "error while parsing \"" + s.path + "\"");
  430.                     }
  431.                 }
  432.  
  433.                 return false;
  434.             }
  435.  
  436.  
  437.             void addSourcePath(string sourcePath){
  438.                 if(!path::isFolder(sourcePath)){
  439.                     if(!path::isFolder(basePath + sourcePath))
  440.                         throw Exception("folder \"" + sourcePath + "\" not found");
  441.                     sourcePath = basePath + sourcePath;
  442.                 }
  443.  
  444.                 for(string& entry: path::list(sourcePath)){
  445.                     if(path::isFolder(sourcePath + '/' + entry))
  446.                         addSourcePath(sourcePath + '/' + entry);
  447.                     else {
  448.                         unsigned long extPos = entry.find_last_of('.');
  449.                         if(extPos >= entry.size()) continue;
  450.                         string ext = entry.substr(extPos, entry.size() - extPos);
  451.                         if(ext == ".cpp" || ext == ".c")
  452.                             sourceFiles.push_back({entry, sourcePath + '/' + entry});
  453.                     }
  454.                 }
  455.             }
  456.  
  457.             int TryProgram(const string& s){
  458.                 if(debug)
  459.                     io::writeln(s);
  460.                 return system(s.c_str());
  461.             }
  462.  
  463.             string findFile(const string& base){
  464.                 if(path::isFile(base)) return base;
  465.  
  466.                 for(string& i: includePaths)
  467.                     if(path::isFile(i + '/' + base))
  468.                         return i + '/' + base;
  469.  
  470.                 return "";
  471.             }
  472.  
  473.             string findObj(const string& obj){
  474.                 if(path::isFile(obj)) return obj;
  475.                 if(path::isFile(getObjectPath(obj))) return getObjectPath(obj);
  476.  
  477.                 for(string& i: smartLibs)
  478.                     if(path::isFile(getObjectPath(i + '/' + obj)))
  479.                         return getObjectPath(i + '/' + obj);
  480.  
  481.                 return "";
  482.             }
  483.  
  484.     };
  485. }
  486.  
  487. void ws::app(std::vector<string> args){
  488.     try {
  489.  
  490.         if(args.size() < 2)
  491.             throw ws::Exception("Not enough arguments given");
  492.  
  493.         if(args[1] == "clean"){
  494.             if(args.size() < 3)
  495.                 throw ws::Exception("Not enough arguments given");
  496.             ws::pibuilder builder(args[2]);
  497.             builder.Clean();
  498.         } else if(args[1] == "debug") {
  499.             if(args.size() < 3)
  500.                 throw ws::Exception("Not enough arguments given");
  501.             io::writeln("debugging");
  502.             ws::pibuilder builder(args[2]);
  503.             builder.debug = true;
  504.             if(builder.Compile())
  505.                 builder.Link();
  506.             builder.RunPost();
  507.         } else {
  508.             ws::pibuilder builder(args[1]);
  509.             if(builder.Compile())
  510.                 builder.Link();
  511.             builder.RunPost();
  512.         }
  513.  
  514.     } catch(ws::Exception& e) {
  515.         ws::io::errln(e.msg(), console::white);
  516.     }
  517. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement