codegen/codegen.cpp

Sun, 27 Jul 2014 02:40:21 +0300

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Sun, 27 Jul 2014 02:40:21 +0300
changeset 848
68410477c8bb
parent 845
fec7023e91a7
child 861
83426c5fa732
permissions
-rw-r--r--

- refactoring
- removed the non-CA license option, made CA license a checkbox

/*
 *  LDForge: LDraw parts authoring CAD
 *  Copyright (C) 2013, 2014 Teemu Piippo
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include <sstream>
#include <fstream>
#include <string>
#include <cstring>
#include <iostream>
#include <vector>
#include <algorithm>

using std::string;
using std::vector;
using std::ifstream;
using std::size_t;
using std::strncmp;
using std::getline;
using std::cout;
using std::endl;

struct entry_type
{
	string name;
	string type;
	string defvalue;

	inline bool operator< (entry_type const& other) const
	{
		return name < other.name;
	}

	inline bool operator== (entry_type const& other) const
	{
		return name == other.name and type == other.type;
	}

	inline bool operator!= (entry_type const& other) const
	{
		return not operator== (other);
	}
};

char advance_pointer (char const*& ptr)
{
	char a = *ptr++;
	if (*ptr == '\0')
		throw false;

	return a;
}

void read_cfgentries (string const& filename, vector<entry_type>& entries, const char* macroname)
{
	ifstream is (filename.c_str());
	string line;
	size_t const macrolen = strlen (macroname);

	while (getline (is, line))
	{
		try
		{
			if (strncmp (line.c_str(), macroname, macrolen) != 0)
				continue;

			char const* ptr = &line[macrolen];
			entry_type entry;

			// Skip to paren
			while (*ptr != '(')
				advance_pointer (ptr);

			// Skip whitespace
			while (isspace (*ptr))
				advance_pointer (ptr);

			// Skip paren
			advance_pointer (ptr);

			// Read type
			while (*ptr != ',')
				entry.type += advance_pointer (ptr);

			// Skip comma and whitespace
			for (advance_pointer (ptr); isspace (*ptr); advance_pointer (ptr))
				;

			// Read name
			while (*ptr != ',')
				entry.name += advance_pointer (ptr);

			// Skip comma and whitespace
			for (advance_pointer (ptr); isspace (*ptr); advance_pointer (ptr))
				;

			// Read default
			while (*ptr != ')')
				entry.defvalue += advance_pointer (ptr);

			entries.push_back (entry);
		}
		catch (bool) {}
	}
}

bool check_equality (vector<entry_type> a, vector<entry_type> b)
{
	if (a.size() != b.size())
		return false;

	std::sort (a.begin(), a.end());
	std::sort (b.begin(), b.end());

	for (size_t i = 0; i < a.size(); ++i)
	{
		if (a[i] != b[i])
			return false;
	}

	return true;
}

int main (int argc, char* argv[])
{
	vector<entry_type> entries;
	vector<entry_type> oldentries;
	read_cfgentries (argv[argc - 1], oldentries, "CODEGEN_CACHE");

	for (int arg = 1; arg < argc - 1; ++arg)
		read_cfgentries (argv[arg], entries, "CFGENTRY");

	if (check_equality (entries, oldentries))
	{
		cout << "Configuration options unchanged" << endl;
	}
	else
	{
		std::ofstream os (argv[argc - 1]);
		os << "#pragma once" << endl;
		os << "#define CODEGEN_CACHE(A,B,C)" << endl;

		for (vector<entry_type>::const_iterator it = entries.begin(); it != entries.end(); ++it)
			os << "CODEGEN_CACHE (" << it->type << ", " << it->name << ", " << it->defvalue << ")" << endl;

		os << endl;
		for (vector<entry_type>::const_iterator it = entries.begin(); it != entries.end(); ++it)
			os << "EXTERN_CFGENTRY (" << it->type << ", " << it->name << ")" << endl;

		os << endl;
		os << "static void InitConfigurationEntry (AbstractConfigEntry* entry);" << endl;
		os << "static void SetupConfigurationLists()" << endl;
		os << "{" << endl;

		for (vector<entry_type>::const_iterator it = entries.begin(); it != entries.end(); ++it)
		{
			os << "\tInitConfigurationEntry (new " << it->type << "ConfigEntry (&cfg::" <<
				it->name << ", \"" << it->name << "\", " << it->defvalue << "));" << endl;
		}

		os << "}" << endl;

		cout << "Wrote configuration options list to " << argv[argc - 1] << "." << endl;
	}

	return 0;
}

mercurial