浏览代码

- Change strncpy to memcpy when parsing switches in the script engine since it's guaranteed to be a word of that size (skip_word).
- Made scriptlabel_db duplicate the key. When str_buf is reallocated, the keys in scriptlabel_db could become invalid, causing a crash in npc_convertlabel_db.
( removed the readded >=0x81 equivalent )
- Now npc_convertlabel_db clears scriptlabel_db after using it.
- parse_script has an extra parameter options. At the moment it only indicates if scriptlabel_db should be used or not.
- Fixed "UINT_MAX undeclared" on systems that don't declare it in limits.h

git-svn-id: https://svn.code.sf.net/p/rathena/svn/trunk@9557 54d463be-8e91-2dee-dedb-b68131a5f0ec

FlavioJS 18 年之前
父节点
当前提交
e75a8eca56
共有 9 个文件被更改,包括 83 次插入61 次删除
  1. 11 0
      Changelog-Trunk.txt
  2. 4 0
      src/common/cbasetypes.h
  3. 1 1
      src/common/db.h
  4. 4 2
      src/common/timer.c
  5. 5 5
      src/map/itemdb.c
  6. 13 13
      src/map/npc.c
  7. 1 1
      src/map/pet.c
  8. 39 38
      src/map/script.c
  9. 5 1
      src/map/script.h

+ 11 - 0
Changelog-Trunk.txt

@@ -3,6 +3,17 @@ Date	Added
 AS OF SVN REV. 5091, WE ARE NOW USING TRUNK.  ALL UNTESTED BUGFIXES/FEATURES GO INTO TRUNK.
 IF YOU HAVE A WORKING AND TESTED BUGFIX PUT IT INTO STABLE AS WELL AS TRUNK.
 
+2006/12/22
+	* Change strncpy to memcpy when parsing switches in the script engine 
+	  since it's guaranteed to be a word of that size (skip_word).
+	* Made scriptlabel_db duplicate the key. When str_buf is reallocated, the 
+	  keys in scriptlabel_db could become invalid, causing a crash in 
+	  npc_convertlabel_db.
+	* Now npc_convertlabel_db clears scriptlabel_db after using it.
+	* parse_script has an extra parameter options. At the moment it only 
+	  indicates if scriptlabel_db should be used or not.
+	* Fixed "UINT_MAX undeclared" on systems that don't declare it in limits.h
+	  [FlavioJS]
 2006/12/21
 	* Applied Rayce's suggestions and fixes to the script engine
 	  (http://www.eathena.ws/board/index.php?showtopic=129185)

+ 4 - 0
src/common/cbasetypes.h

@@ -126,6 +126,10 @@ typedef unsigned int		uint32;
 #define SINT16_MAX	((sint16)0x7FFF)
 #define SINT32_MAX	((sint32)0x7FFFFFFF)
 
+// ILP64 isn't supported, so always 32 bits?
+#ifndef UINT_MAX
+#define UINT_MAX 0xFFFFFFFF
+#endif
 
 //////////////////////////////////////////////////////////////////////////
 // Integers with guaranteed _minimum_ size.

+ 1 - 1
src/common/db.h

@@ -130,7 +130,7 @@ typedef enum {
  * @see #db_default_release(DBType,DBOptions)
  * @see #db_alloc(const char *,int,DBType,DBOptions,unsigned short)
  */
-typedef enum {
+typedef enum db_opt {
 	DB_OPT_BASE            = 0,
 	DB_OPT_DUP_KEY         = 1,
 	DB_OPT_RELEASE_KEY     = 2,

+ 4 - 2
src/common/timer.c

@@ -18,9 +18,11 @@
 #include <stdlib.h>
 #include <string.h>
 #include <time.h>
+
+#include "../common/cbasetypes.h"
+#include "../common/malloc.h"
+#include "../common/showmsg.h"
 #include "timer.h"
-#include "malloc.h"
-#include "showmsg.h"
 
 // タイマー間隔の最小値。モンスターの大量召還時、多数のクライアント接続時に
 // サーバーが反応しなくなる場合は、TIMER_MIN_INTERVAL を増やしてください。

+ 5 - 5
src/map/itemdb.c

@@ -1146,11 +1146,11 @@ static int itemdb_readdb(void)
 				np = strchr(np+1,'}'); //Jump close brackets until the next field is found.
 			if (!np || !np[1]) {
 				//Couldn't find the end of the script field.
-				id->script = parse_script((unsigned char *) str[19],filename[i],lines);
+				id->script = parse_script(str[19],filename[i],lines,0);
 				continue;
 			}
 			np[1] = '\0'; //Set end of script
-			id->script = parse_script((unsigned char *) str[19],filename[i],lines);
+			id->script = parse_script(str[19],filename[i],lines,0);
 			np+=2; //Skip to next field
 			
 			if(!np || (p=strchr(np,'{'))==NULL)
@@ -1163,18 +1163,18 @@ static int itemdb_readdb(void)
 				np = strchr(np+1,'}'); //Jump close brackets until the next field is found.
 			if (!np || !np[1]) {
 				//Couldn't find the end of the script field.
-				id->equip_script = parse_script((unsigned char *) str[20],filename[i],lines);
+				id->equip_script = parse_script(str[20],filename[i],lines,0);
 				continue;
 			}
 			
 			np[1] = '\0'; //Set end of script
-			id->equip_script = parse_script((unsigned char *) str[20],filename[i],lines);
+			id->equip_script = parse_script(str[20],filename[i],lines,0);
 			np+=2; //Skip comma, to next field
 			
 			if(!np || (p=strchr(np,'{'))==NULL)
 				continue;
 			//Unequip script, last column.
-			id->unequip_script = parse_script((unsigned char *) p,filename[i],lines);
+			id->unequip_script = parse_script(p,filename[i],lines,0);
 		}
 		fclose(fp);
 		if (ln > 0) {

+ 13 - 13
src/map/npc.c

@@ -1725,13 +1725,13 @@ static int npc_parse_shop (char *w1, char *w2, char *w3, char *w4)
  */
 int npc_convertlabel_db (DBKey key, void *data, va_list ap)
 {
-	unsigned char *lname = key.str;
+	const char *lname = (const char*)key.str;
 	int pos = (int)data;
 	struct npc_data *nd;
 	struct npc_label_list *lst;
 	int num;
-	char *p;
-	char c;
+	const char *p;
+	int len;
 
 	nullpo_retr(0, ap);
 	nullpo_retr(0, nd = va_arg(ap,struct npc_data *));
@@ -1746,18 +1746,17 @@ int npc_convertlabel_db (DBKey key, void *data, va_list ap)
 
 	// In case of labels not terminated with ':', for user defined function support
 	p = lname;
-	while(isalnum(*(unsigned char*)p) || *p == '_') { p++; }
-	c = *p;
-	*p='\0';
+	while( ISALNUM(*p) || *p == '_' )
+		p++;
+	len = p-lname;
 
 	// here we check if the label fit into the buffer
-	if (strlen(lname) > 23) {
+	if (len > 23) {
 		ShowError("npc_parse_script: label name longer than 23 chars! '%s'\n (%s)", lname, current_file);
 		exit(1);
 	}
-	memcpy(lst[num].name, lname, strlen(lname)+1); //including EOS
-
-	*p = c;
+	memcpy(lst[num].name, lname, len);
+	lst[num].name[len]=0;
 	lst[num].pos = pos;
 	nd->u.scr.label_list = lst;
 	nd->u.scr.label_list_num = num+1;
@@ -1868,7 +1867,7 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line
 	unsigned char line[1024];
 	int i;
 	struct npc_data *nd, *dnd;
-	struct dbt *label_db;
+	DB label_db;
 	char *p;
 	struct npc_label_list *label_dup = NULL;
 	int label_dupnum = 0;
@@ -1920,7 +1919,7 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line
 			script = NULL;
 		} else {
 			// printf("Ok line %d\n",*lines);
-			script = parse_script((unsigned char *) srcbuf, file, startline);
+			script = parse_script(srcbuf, file, startline, SCRIPT_USE_LABEL_DB);
 		}
 		if (script == NULL) {
 			// script parse error?
@@ -2039,6 +2038,7 @@ static int npc_parse_script(char *w1,char *w2,char *w3,char *w4,char *first_line
 		// ラベルデータのコンバート
 		label_db = script_get_label_db();
 		label_db->foreach(label_db, npc_convertlabel_db, nd);
+		label_db->clear(label_db,NULL); // not needed anymore, so clear the db
 
 		// もう使わないのでバッファ解放
 		aFree(srcbuf);
@@ -2156,7 +2156,7 @@ static int npc_parse_function (char *w1, char *w2, char *w3, char *w4, char *fir
 		ShowError("Missing right curly at file %s, line %d\n",file, *lines);
 		script = NULL;
 	} else {
-		script = parse_script(srcbuf, file, startline);
+		script = parse_script(srcbuf, file, startline,0);
 	}
 	if (script == NULL) {
 		// script parse error?

+ 1 - 1
src/map/pet.c

@@ -1351,7 +1351,7 @@ int read_petdb()
 			pet_db[j].script = NULL;
 			if((np=strchr(p,'{'))==NULL)
 				continue;
-			pet_db[j].script = parse_script((unsigned char *) np, filename[i], lines);
+			pet_db[j].script = parse_script(np, filename[i], lines, 0);
 			j++;
 		}
 		if (j >= MAX_PET_DB)

+ 39 - 38
src/map/script.c

@@ -88,6 +88,7 @@ char mapreg_txt[256]="save/mapreg.txt";
 
 static struct dbt *scriptlabel_db=NULL;
 static struct dbt *userfunc_db=NULL;
+static int parse_options=0;
 struct dbt* script_get_label_db(){ return scriptlabel_db; }
 struct dbt* script_get_userfunc_db(){ return userfunc_db; }
 
@@ -158,7 +159,7 @@ int mapreg_setreg(int num,int val);
 int mapreg_setregstr(int num,const char *str);
 static void disp_error_message(const char *mes,const char *pos);
 
-enum {
+enum c_op {
 	C_NOP,C_POS,C_INT,C_PARAM,C_FUNC,C_STR,C_CONSTSTR,C_ARG,
 	C_NAME,C_EOL, C_RETINFO,
 	C_USERFUNC, C_USERFUNC_POS, // user defined functions
@@ -502,12 +503,8 @@ static const char *skip_word(const char *p)
 	//# Changing from unsigned char to signed char makes p never be able to go above 0x81, but what IS 0x81 for? [Skotlex]
 	//# It's for multibyte encodings like Shift-JIS. Unfortunately this can be problematic for singlebyte encodings.
 	//  Using (*p)>>7 would yield the appropriate result but it's better to restrict words to ASCII characters only. [FlavioJS]
-	while( ISALNUM(*p) || *p == '_' || (*p)>>7 )
-	{
-		if( (*p)>>7 ) // readded the >=0x81 equivalent until I figure out where the script engine is 'being naughty' O.o [FlavioJS]
-			++p;
+	while( ISALNUM(*p) || *p == '_' )
 		++p;
-	}
 	// postfix
 	if(*p=='$') p++;	// 文字列変数
 
@@ -1020,12 +1017,12 @@ const char* parse_syntax(const char* p) {
 				p = skip_space(p);
 				p2 = p;
 				p = skip_word(p);
-				len = p-p2;
+				len = p-p2; // length of word at p2
 				p = skip_space(p);
 				if(*p != ':')
 					disp_error_message("parse_syntax: expect ':'",p);
 				memcpy(label,"if(",3);
-				strncpy(label+3,p2,len);
+				memcpy(label+3,p2,len);
 				sprintf(label+3+len," != $@__SW%x_VAL) goto __SW%x_%x;",
 					syntax.curly[pos].index,syntax.curly[pos].index,syntax.curly[pos].count+1);
 				syntax.curly[syntax.curly_count++].type = TYPE_NULL;
@@ -1254,7 +1251,8 @@ const char* parse_syntax(const char* p) {
 				if(str_data[l].type == C_NOP)
 					str_data[l].type = C_USERFUNC;
 				set_label(l,script_pos,p);
-				strdb_put(scriptlabel_db, GETSTRING(str_data[l].str), (void*)script_pos);
+				if( parse_options&SCRIPT_USE_LABEL_DB )
+					strdb_put(scriptlabel_db, GETSTRING(str_data[l].str), (void*)script_pos);
 				return skip_space(p);
 			}
 		}
@@ -1562,7 +1560,22 @@ static void read_constdb(void)
  *------------------------------------------
  */
 
-const char* script_print_line( const char *p, const char *mark, int line );
+const char* script_print_line( const char *p, const char *mark, int line ) {
+	int i;
+	if( p == NULL || !p[0] ) return NULL;
+	if( line < 0 ) 
+		printf("*% 5d : ", -line);
+	else
+		printf(" % 5d : ", line);
+	for(i=0;p[i] && p[i] != '\n';i++){
+		if(p + i != mark)
+			printf("%c",p[i]);
+		else
+			printf("\'%c\'",p[i]);
+	}
+	printf("\n");
+	return p+i+(p[i] == '\n' ? 1 : 0);
+}
 
 void script_error(const char *src,const char *file,int start_line, const char *error_msg, const char *error_pos) {
 	// エラーが発生した行を求める
@@ -1595,29 +1608,12 @@ void script_error(const char *src,const char *file,int start_line, const char *e
 	}
 }
 
-const char* script_print_line( const char *p, const char *mark, int line ) {
-	int i;
-	if( p == NULL || !p[0] ) return NULL;
-	if( line < 0 ) 
-		printf("*% 5d : ", -line);
-	else
-		printf(" % 5d : ", line);
-	for(i=0;p[i] && p[i] != '\n';i++){
-		if(p + i != mark)
-			printf("%c",p[i]);
-		else
-			printf("\'%c\'",p[i]);
-	}
-	printf("\n");
-	return p+i+(p[i] == '\n' ? 1 : 0);
-}
-
 /*==========================================
  * スクリプトの解析
  *------------------------------------------
  */
 
-struct script_code* parse_script(const char *src,const char *file,int line)
+struct script_code* parse_script(const char *src,const char *file,int line,int options)
 {
 	const char *p,*tmpp;
 	int i;
@@ -1648,8 +1644,11 @@ struct script_code* parse_script(const char *src,const char *file,int line)
 		}
 	}
 
-	//Labels must be reparsed for the script....
-	scriptlabel_db->clear(scriptlabel_db, NULL);
+	// who called parse_script is responsible for clearing the database after using it, but just in case... lets clear it here
+	if( options&SCRIPT_USE_LABEL_DB )
+		scriptlabel_db->clear(scriptlabel_db, NULL);
+	parse_options = options;
+
 	if( setjmp( error_jump ) != 0 ) {
 		//Restore program state when script has problems. [from jA]
 		script_error(src,file,line,error_msg,error_pos);
@@ -1688,7 +1687,8 @@ struct script_code* parse_script(const char *src,const char *file,int line)
 		if(*tmpp==':' && !(!strncmp(p,"default:",8) && p + 7 == tmpp)){
 			i=add_word(p);
 			set_label(i,script_pos,p);
-			strdb_put(scriptlabel_db, GETSTRING(str_data[i].str), (void*)script_pos);
+			if( parse_options&SCRIPT_USE_LABEL_DB )
+				strdb_put(scriptlabel_db, GETSTRING(str_data[i].str), (void*)script_pos);
 			p=tmpp+1;
 			continue;
 		}
@@ -1955,8 +1955,9 @@ char* conv_str(struct script_state *st,struct script_data *data)
 	get_val(st,data);
 	if(data->type==C_INT){
 		char *buf;
-		buf=(char *)aMallocA(ITEM_NAME_LENGTH*sizeof(char));
+		CREATE(buf,char,ITEM_NAME_LENGTH);
 		snprintf(buf,ITEM_NAME_LENGTH, "%d",data->u.num);
+		buf[ITEM_NAME_LENGTH-1]=0;
 		data->type=C_STR;
 		data->u.str=buf;
 	} else if(data->type==C_POS) {
@@ -3273,7 +3274,7 @@ int do_init_script()
 	mapreg_db= db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_BASE,sizeof(int));
 	mapregstr_db=db_alloc(__FILE__,__LINE__,DB_INT,DB_OPT_RELEASE_DATA,sizeof(int));
 	userfunc_db=db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_RELEASE_BOTH,50);
-	scriptlabel_db=db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_ALLOW_NULL_DATA,50);
+	scriptlabel_db=db_alloc(__FILE__,__LINE__,DB_STRING,DB_OPT_DUP_KEY|DB_OPT_ALLOW_NULL_DATA,50);
 	
 	script_load_mapreg();
 
@@ -3978,9 +3979,9 @@ struct script_function buildin_func[] = {
 int buildin_mes(struct script_state *st)
 {
 	struct map_session_data *sd = script_rid2sd(st);
-	conv_str(st,& (st->stack->stack_data[st->start+2]));
+	char *mes = conv_str(st, &(st->stack->stack_data[st->start+2]));
 	if (sd)
-		clif_scriptmes(sd,st->oid,st->stack->stack_data[st->start+2].u.str);
+		clif_scriptmes(sd, st->oid, mes);
 	return 0;
 }
 
@@ -11306,9 +11307,9 @@ int buildin_setbattleflag(struct script_state *st){
 	value = conv_str(st,& (st->stack->stack_data[st->start+3]));
 	
 	if (battle_set_value(flag, value) == 0)
-		ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'",flag);
+		ShowWarning("buildin_setbattleflag: unknown battle_config flag '%s'\n",flag);
 	else
-		ShowInfo("buildin_setbattleflag: battle_config flag '%s' is now set to '%s'.",flag,value);
+		ShowInfo("buildin_setbattleflag: battle_config flag '%s' is now set to '%s'.\n",flag,value);
 
 	return 0;
 }
@@ -11800,7 +11801,7 @@ int buildin_setitemscript(struct script_state *st)
 	if (i_data && script!=NULL && script[0]=='{') {
 		if(i_data->script!=NULL)
 			script_free_code(i_data->script);
-		i_data->script = parse_script(script, "script_setitemscript", 0);
+		i_data->script = parse_script(script, "script_setitemscript", 0, 0);
 		push_val(st->stack,C_INT,1);
 	} else
 		push_val(st->stack,C_INT,0);

+ 5 - 1
src/map/script.h

@@ -61,7 +61,11 @@ struct script_state {
 	} sleep;
 };
 
-struct script_code* parse_script(const char* src,const char* file,int line);
+enum script_parse_options {
+	SCRIPT_USE_LABEL_DB = 0x1
+};
+
+struct script_code* parse_script(const char* src,const char* file,int line,int options);
 void run_script_sub(struct script_code *rootscript,int pos,int rid,int oid, char* file, int lineno);
 void run_script(struct script_code*,int,int,int);