git » fp-git.git » master » tree

[master] / PR / src / lib / layers / resourcematch.c

/*  Princed V3 - Prince of Persia Level Editor for PC Version
    Copyright (C) 2003 Princed Development Team

    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 2 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, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    The authors of this program may be contacted at http://forum.princed.com.ar
*/

/*
resourcematch.c: Princed Resources : Partial list matching abstract layer
���������������
 Copyright 2005 Princed Development Team
  Created: 18 Dec 2005

  Author: Enrique Calot <ecalot.cod@princed.com.ar>
  Version: 1.01 (2005-Dec-18)

 Note:
  DO NOT remove this copyright notice
*/

#include "memory.h"
#include "resourcematch.h"
#include "translate.h" /* translate */
#include <stdio.h>

#define dVal 1
#define dInd 2
#define dOrd 4
#define dPat 8

#define nVal 16
#define nInd 32
#define nOrd 64
#define nPat 128

typedef enum {eDone=0,eVal,eInd,eOrd,ePat} tStatus;

char aux[200];

/* default values */
static tResourceMatch result;

void freeRM(tResourceMatch *r) {
	freeAllocation(r->index);
	freeAllocation(r->path);
}

void rm_emit(tStatus s, char c) {
	static tStatus old=eDone;
	static char* a=aux;
	static int x=0;

	if (s!=old) { /* status change */
		*a=0;x=0;
		switch (old) {
		case eVal:result.value=atoi(aux);break;
		case eInd:result.index=strallocandcopy(aux);break;
		case eOrd:result.order=getOrder(aux);break;
		case ePat:result.path =strallocandcopy(aux);break;
		default:break;
		}
		old=s;
		a=aux;
	}
	if (x==199) {*a=0;return;} /* oops, "aux" size limit has been reached. this return avoids a buffer overflow */
	*(a++)=c;
	x++;
}

int initRM(const char* text, tResourceMatch *r) {
	tStatus status=eVal;
	const char* t;

	/* set up default values */
	result.flag=0;
	result.value=0;
	result.order=0;
	result.index=NULL;
	result.path=NULL;

	for (t=text;status!=eDone;t++) {
		switch (*t) {
		case '!':
			if (*(t+1)=='/' || *(t+1)=='\\') {
				result.flag|=nPat;
			} else {
				if (status==eVal) {
					if (t!=text) return PR_RESULT_F_COMMAND_LINE_SYNTAX; /* one ! inside the val number */
					result.flag|=nVal;
				} else { /* default action */
					rm_emit(status,*t);
				}
			}
			break;
		case '\\':
		case '/': /* path */
			status=ePat;
			result.flag|=dPat;
			rm_emit(status,'/'); /* starts with / */
			break;
		case ':': /* index */
			if (status!=ePat) { /* after path, no index is allowed */
				if (*(t+1)=='!') {
					result.flag|=nInd;
					t++;
				}
				status=eInd;
				if (result.flag&dInd) {
					freeRM(&result);
					return PR_RESULT_F_COMMAND_LINE_SYNTAX; /* ind flag has been set, duplicated index? */
				}
				result.flag|=dInd;
			} else rm_emit(status,*t);
			break;
		case '#': /* order */
			if (status!=ePat) { /* after path, no order is allowed */
				if (*(t+1)=='!') {
					result.flag|=nOrd;
					t++;
				}
				status=eOrd;
				if (result.flag&dOrd) {
					freeRM(&result);
					return PR_RESULT_F_COMMAND_LINE_SYNTAX; /* ord flag has been set, duplicated order? */
				}
				result.flag|=dOrd;
			} else rm_emit(status,*t);
			break;
		case 0:
			status=eDone;
			break;
		default: /* by default "value" */
			if (status==eVal) result.flag|=dVal;
			rm_emit(status,*t);
			break;
		}
	}
	rm_emit(eDone,0);
	*r=result;

	if ( ( !(result.flag&dVal) ) && ( result.flag&nVal ) )
		return PR_RESULT_F_COMMAND_LINE_SYNTAX; /* check for this particular case: @!: */

	return PR_RESULT_SUCCESS; /* Ok */
}

/* matches becomes false only if the flag is true and the match is false */
#define rm_compare(n,x,a) m=m&&( (!(r->flag&x)) || ( (!(a)) != (!(r->flag&n)) ))

int runRM(const tResourceMatch *r, const char* path, const tResourceId *id) {
	int m=1; /* by default it matches */
	const char* null="";
	const char* rpath;
	const char* rindex;

#ifdef DEBUG_MATCH
	printf("Matching: path='%s', id=(%d,%s,%d) <=> flag=%x path='%s' id=(%d,%s,%d)\n",
		path,
		id->value,id->index,id->order,
		r->flag,
		r->path,
		r->value,r->index,r->order
	);
#endif

	/* replace NULL with null */
	rindex=r->index?r->index:null;
	rpath=r->path?r->path:null;

	/* rm_compare each field */
	rm_compare(nOrd,dOrd,r->order==id->order);
	rm_compare(nVal,dVal,r->value==id->value);
	rm_compare(nInd,dInd,matchesIn(id->index,rindex)||matchesIn(translateInt2Ext(id->index),rindex));
	rm_compare(nPat,dPat,matchesIn(path,rpath));

	return m;
}