├── .gitignore ├── LICENSE ├── README.md ├── merger.js ├── package-lock.json └── package.json /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2016, Wim Goeman 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Automatic merger for C/C++ in the CodinGame IDE 2 | 3 | ## Install 4 | ### Prerequisites 5 | 6 | * Node.js 7 | * npm (part of node) 8 | 9 | ### Installation from npm 10 | ``` 11 | npm i -g codingame-cpp-merge 12 | ``` 13 | 14 | ### Installation from source 15 | * Clone this repo 16 | * issue npm link 17 | ``` 18 | git clone https://github.com/wimgoeman/codingame-cpp-merge.git 19 | cd codingame-cpp-merge 20 | npm link 21 | ``` 22 | 23 | ## Usage 24 | This tool will scan the working dir for cpp files recursively and append them 25 | all to a single file. While doing this, includes are processed similar to what 26 | the preprocessor would do. 27 | 28 | See built-in help for possible options: 29 | ``` 30 | codingame-merge -h 31 | ``` 32 | 33 | * Create a directory tree with cpp and hpp files 34 | * Do not use other extensions than hpp and cpp (more extension support may be added later) 35 | * Use #include <> for libraries 36 | * Use #include "" for local files 37 | * Set up include guards in your hpp files, or use '#pragma once' 38 | * Prefer pragma once over include guards to limit output size 39 | -------------------------------------------------------------------------------- /merger.js: -------------------------------------------------------------------------------- 1 | #! /usr/bin/env node 2 | "use strict" 3 | const fs = require('fs'); 4 | const path = require('path'); 5 | const readline = require('readline'); 6 | const opt = require('node-getopt').create([ 7 | ['h', 'help', 'Display this help'], 8 | ['o', 'output=FILE', 'File to write merged output to.'], 9 | ['w', 'working-dir=DIR', 'Directory holding the cpp files.'], 10 | ['e', 'exclude-dir=DIR', 'Directory in the working dir to exclude from the merge.'], 11 | ['m', 'main-file=FILE', 'File to start with'] 12 | ]) 13 | .bindHelp() 14 | .parseSystem(); 15 | 16 | var workDir = opt.options['working-dir'] ? opt.options['working-dir'] : '.'; 17 | var outputFile = opt.options['output'] ? opt.options['output'] : 'merged'; 18 | var excludeDir = opt.options['exclude-dir'] ? opt.options['exclude-dir'] : 'generated'; 19 | var mainFile = opt.options['main-file'] ? path.join(workDir, opt.options['main-file']): null; 20 | var mainIsProcessed = false; 21 | var processOnce = []; //Array holds files which had '#pragma once' 22 | 23 | //Wipe file to start 24 | fs.writeFileSync(outputFile, ""); 25 | 26 | 27 | if (mainFile) { 28 | processFile(mainFile, false); 29 | mainIsProcessed = true; 30 | } 31 | 32 | processDir(workDir); 33 | 34 | 35 | function processDir(dir) 36 | { 37 | let nodes = fs.readdirSync(dir); 38 | for (let i = 0; i < nodes.length; i++) 39 | { 40 | let node = nodes[i]; 41 | let fullPath = path.join(dir, node); 42 | let stat = fs.statSync(fullPath); 43 | if (stat.isDirectory() && path.basename(fullPath) != excludeDir) { 44 | processDir(fullPath); 45 | } else if (stat.isFile()) { 46 | processFile(fullPath, false); 47 | } 48 | } 49 | } 50 | 51 | function processFile(file, include) { 52 | let processedOnce = false; 53 | for (let i = 0; i < processOnce.length; i++) { 54 | if (processOnce[i] == file) { 55 | processedOnce = true; 56 | break; 57 | } 58 | } 59 | 60 | if (file === mainFile && mainIsProcessed || file == outputFile) { 61 | return; //Main can be processed on its own at the start 62 | } else if (path.extname(file) == ".hpp" && !include) { 63 | return; 64 | } else if (path.extname(file) == ".cpp") { 65 | console.log('Processing ' + file); 66 | fs.appendFileSync(outputFile, "/*-- File: " + file + " start --*/\n"); 67 | } else if (path.extname(file) == ".hpp" || path.extname(file) == ".h") { 68 | console.log("Including: ", file); 69 | fs.appendFileSync(outputFile, "/*-- #include \"" + file + "\" start --*/\n"); 70 | } else { 71 | //File can be ignored 72 | return; 73 | } 74 | 75 | 76 | if (!processedOnce) { 77 | let fileContent = fs.readFileSync(file, {encoding: "utf8"}); 78 | let lines = fileContent.split("\n"); 79 | for (let i = 0; i < lines.length; i++) { 80 | let line = lines[i]; 81 | if (line.indexOf("#include \"") >= 0) { 82 | let includedFile = line.substring(line.indexOf("\"") + 1, line.lastIndexOf("\"")); 83 | includedFile = path.join(path.dirname(file), includedFile); 84 | processFile(includedFile, true); 85 | } else if (line.indexOf("#pragma once") >= 0) { 86 | processOnce.push(file); 87 | } else { 88 | fs.appendFileSync(outputFile, line + "\n"); 89 | } 90 | } 91 | } 92 | 93 | if (path.extname(file) == ".cpp") { 94 | fs.appendFileSync(outputFile, "/*-- File: " + file + " end --*/\n"); 95 | } else if (path.extname(file) == ".hpp") { 96 | fs.appendFileSync(outputFile, "/*-- #include \"" + file + "\" end --*/\n"); 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codingame-cpp-merge", 3 | "version": "0.0.5", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "node-getopt": { 8 | "version": "0.2.3", 9 | "resolved": "https://registry.npmjs.org/node-getopt/-/node-getopt-0.2.3.tgz", 10 | "integrity": "sha1-aau8flQAYA0drPANuMt5tUh+kks=" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "codingame-cpp-merge", 3 | "version": "0.0.5", 4 | "description": "Automatic merger for C/C++ in the CodinGame IDE", 5 | "main": "merger.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [ 10 | "CodinGame", 11 | "C", 12 | "C++", 13 | "merge" 14 | ], 15 | "author": "Wim Goeman", 16 | "license": "ISC", 17 | "repository": { 18 | "type": "git", 19 | "url": "https://github.com/wimgoeman/codingame-cpp-merge.git" 20 | }, 21 | "dependencies": { 22 | "node-getopt": "^0.2.3" 23 | }, 24 | "bin": { 25 | "codingame-merge": "merger.js" 26 | } 27 | } 28 | --------------------------------------------------------------------------------