src/commands.cxx

Fri, 10 Jan 2014 21:58:42 +0200

author
Teemu Piippo <crimsondusk64@gmail.com>
date
Fri, 10 Jan 2014 21:58:42 +0200
changeset 72
03e4d9db3fd9
parent 71
11f23fabf8a6
child 73
1ee9b312dc18
permissions
-rw-r--r--

- major refactoring begins

/*
 *	botc source code
 *	Copyright (C) 2012 Santeri `Dusk` Piippo
 *	All rights reserved.
 *	
 *	Redistribution and use in source and binary forms, with or without
 *	modification, are permitted provided that the following conditions are met:
 *	
 *	1. Redistributions of source code must retain the above copyright notice,
 *	   this list of conditions and the following disclaimer.
 *	2. Redistributions in binary form must reproduce the above copyright notice,
 *	   this list of conditions and the following disclaimer in the documentation
 *	   and/or other materials provided with the distribution.
 *	3. Neither the name of the developer nor the names of its contributors may
 *	   be used to endorse or promote products derived from this software without
 *	   specific prior written permission.
 *	4. Redistributions in any form must be accompanied by information on how to
 *	   obtain complete source code for the software and any accompanying
 *	   software that uses the software. The source code must either be included
 *	   in the distribution or be available for no more than the cost of
 *	   distribution plus a nominal fee, and must be freely redistributable
 *	   under reasonable conditions. For an executable file, complete source
 *	   code means the source code for all modules it contains. It does not
 *	   include source code for modules or files that typically accompany the
 *	   major components of the operating system on which the executable file
 *	   runs.
 *	
 *	THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 *	AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 *	IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 *	ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
 *	LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 *	CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 *	SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 *	INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 *	CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 *	ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *	POSSIBILITY OF SUCH DAMAGE.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "main.h"
#include "scriptreader.h"
#include "str.h"
#include "commands.h"

CommandDef* g_CommDef;

// ============================================================================
// Reads command definitions from commands.def and stores them to memory.
void ReadCommands () {
	ScriptReader* r = new ScriptReader ("commands.def");
	g_CommDef = null;
	CommandDef* curdef = g_CommDef;
	unsigned int numCommDefs = 0;
	
	while (r->PeekNext().len()) {
		CommandDef* comm = new CommandDef;
		comm->next = null;
		
		// Number
		r->MustNumber ();
		comm->number = r->token.to_long();
		
		r->MustNext (":");
		
		// Name
		r->MustNext ();
		comm->name = r->token;
		if (IsKeyword (comm->name))
			r->ParserError ("command name `%s` conflicts with keyword", comm->name.chars());
		
		r->MustNext (":");
		
		// Return value
		r->MustNext ();
		comm->returnvalue = GetTypeByName (r->token);
		if (comm->returnvalue == -1)
			r->ParserError ("bad return value type `%s` for command %s", r->token.chars(), comm->name.chars());
		
		r->MustNext (":");
		
		// Num args
		r->MustNumber ();
		comm->numargs = r->token.to_long();
		
		r->MustNext (":");
		
		// Max args
		r->MustNumber ();
		comm->maxargs = r->token.to_long();
		
		if (comm->maxargs > MAX_MAXARGS)
			r->ParserError ("maxargs (%d) greater than %d!", comm->maxargs, MAX_MAXARGS);
		
		// Argument types
		int curarg = 0;
		while (curarg < comm->maxargs) {
			r->MustNext (":");
			r->MustNext ();
			
			type_e type = GetTypeByName (r->token);
			if (type == -1)
				r->ParserError ("bad argument %d type `%s`", curarg, r->token.chars());
			if (type == TYPE_VOID)
				r->ParserError ("void is not a valid argument type!");
			comm->argtypes[curarg] = type;
			
			r->MustNext ("(");
			r->MustNext ();
			
			// - 1 because of terminating null character
			if (r->token.len() > MAX_ARGNAMELEN - 1)
				r->ParserWarning ("argument name is too long (%d, max is %d)",
					r->token.len(), MAX_ARGNAMELEN - 1);
			
			strncpy (comm->argnames[curarg], r->token.chars(), MAX_ARGNAMELEN);
			comm->argnames[curarg][MAX_ARGNAMELEN-1] = 0;
			
			// If this is an optional parameter, we need the default value.
			if (curarg >= comm->numargs) {
				r->MustNext ("=");
				switch (type) {
				case TYPE_INT:
				case TYPE_BOOL:
					r->MustNumber();
					break;
				case TYPE_STRING:
					r->MustString();
					break;
				case TYPE_UNKNOWN:
				case TYPE_VOID:
					break;
				}
				
				comm->defvals[curarg] = r->token.to_long();
			}
			
			r->MustNext (")");
			curarg++;
		}
		
		if (!g_CommDef)
			g_CommDef = comm;
		
		if (!curdef) {
			curdef = comm;
		} else {
			curdef->next = comm;
			curdef = comm;
		}
		numCommDefs++;
	}
	
	if (!numCommDefs)
		r->ParserError ("no commands defined!\n");
	
	r->CloseFile ();
	delete r;
	printf ("%d command definitions read.\n", numCommDefs);
}

// ============================================================================
// Finds a command by name
CommandDef* FindCommand (string fname) {
	CommandDef* comm;
	ITERATE_COMMANDS (comm) {
		if (fname.to_uppercase() == comm->name.to_uppercase())
			return comm;
	}
	
	return null;
}

// ============================================================================
// Returns the prototype of the command
string GetCommandPrototype (CommandDef* comm) {
	string text;
	text += GetTypeName (comm->returnvalue);
	text += ' ';
	text += comm->name;
	text += '(';
	
	bool hasOptionalArguments = false;
	for (int i = 0; i < comm->maxargs; i++) {
		if (i == comm->numargs) {
			hasOptionalArguments = true;
			text += '[';
		}
		
		if (i)
			text += ", ";
		
		text += GetTypeName (comm->argtypes[i]);
		text += ' ';
		text += comm->argnames[i];
		
		if (i >= comm->numargs) {
			text += '=';
			
			bool isString = comm->argtypes[i] == TYPE_STRING;
			if (isString) text += '"';
			
			char defvalstring[8];
			sprintf (defvalstring, "%d", comm->defvals[i]);
			text += defvalstring;
			
			if (isString) text += '"';
		}
	}
	
	if (hasOptionalArguments)
		text += ']';
	text += ')';
	return text;
}

mercurial