initial import of new format zomg
This commit is contained in:
		| @@ -32,6 +32,7 @@ | ||||
| #include <stdarg.h> | ||||
| #include "amxmodx.h" | ||||
| #include "CLang.h" | ||||
| #include "format.h" | ||||
|  | ||||
| #ifdef __linux__ | ||||
| #define _snprintf snprintf | ||||
| @@ -368,277 +369,13 @@ int CLangMngr::GetKeyEntry(String &key) | ||||
| 	return val.index; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * FORMATTING ROUTINES | ||||
|  */ | ||||
|  | ||||
| #define FMTPM_NEXTPARAM() \ | ||||
| 	if (*param > numParams) { \ | ||||
| 		LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", *param, numParams); \ | ||||
| 		return 0; \ | ||||
| 	} \ | ||||
| 	_addr = params[*param]; \ | ||||
| 	(*param)++; | ||||
|  | ||||
| extern "C" size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output, size_t maxlen, int level); | ||||
| THash<String, lang_err> BadLang_Table; | ||||
|  | ||||
| static cvar_t *amx_mldebug = NULL; | ||||
| static cvar_t *amx_cl_langs = NULL; | ||||
|  | ||||
| extern "C" const char *translate(AMX *amx, cell amxaddr, const char *key) | ||||
| { | ||||
| 	const char *pLangName = NULL; | ||||
| 	const char *def = NULL; | ||||
| 	int status; | ||||
| 	cell *addr = get_amxaddr(amx, amxaddr); | ||||
| 	char name[4]; | ||||
| 	if (addr[0] == LANG_PLAYER) | ||||
| 	{ | ||||
| 		if (!amx_cl_langs) | ||||
| 			amx_cl_langs = CVAR_GET_POINTER("amx_client_languages"); | ||||
| 		if ( (int)amx_cl_langs->value == 0 ) | ||||
| 		{ | ||||
| 			pLangName = g_vault.get("server_language"); | ||||
| 		} else { | ||||
| 			pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(g_langMngr.GetDefLang())->pEdict, "lang"); | ||||
| 		} | ||||
| 	} else if (addr[0] == LANG_SERVER) { | ||||
| 		pLangName = g_vault.get("server_language"); | ||||
| 	} else if (addr[0] >= 1 && addr[0] <= gpGlobals->maxClients) { | ||||
| 		if (!amx_cl_langs) | ||||
| 			amx_cl_langs = CVAR_GET_POINTER("amx_client_languages"); | ||||
| 		if ( (int)amx_cl_langs->value == 0 ) | ||||
| 		{ | ||||
| 			pLangName = g_vault.get("server_language"); | ||||
| 		} else { | ||||
| 			pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(addr[0])->pEdict, "lang"); | ||||
| 		} | ||||
| 	} else { | ||||
| 		get_amxstring_r(amx, amxaddr, name, 3); | ||||
| 		pLangName = name; | ||||
| 	} | ||||
| 	if (!pLangName || !isalpha(pLangName[0])) | ||||
| 		pLangName = "en"; | ||||
| 	//next parameter! | ||||
| 	def = g_langMngr.GetDef(pLangName, key, status); | ||||
| 			 | ||||
| 	if (!amx_mldebug) | ||||
| 		amx_mldebug = CVAR_GET_POINTER("amx_mldebug"); | ||||
|  | ||||
| 	bool debug = (amx_mldebug && amx_mldebug->string && (amx_mldebug->string[0] != '\0')); | ||||
| 		 | ||||
| 	if (debug) | ||||
| 	{ | ||||
| 		int debug_status; | ||||
| 		bool validlang = true; | ||||
| 		const char *testlang = amx_mldebug->string; | ||||
| 		if (!g_langMngr.LangExists(testlang)) | ||||
| 		{ | ||||
| 			AMXXLOG_Log("[AMXX] \"%s\" is an invalid debug language", testlang); | ||||
| 			validlang = false; | ||||
| 		} | ||||
| 				 | ||||
| 		g_langMngr.GetDef(testlang, key, debug_status); | ||||
| 				 | ||||
| 		if (validlang && debug_status == ERR_BADKEY) | ||||
| 			AMXXLOG_Log("[AMXX] Language key \"%s\" not found for language \"%s\", check \"%s\"", key, testlang, GetFileName(amx)); | ||||
| 	} | ||||
| 				 | ||||
| 	if (def == NULL) | ||||
| 	{ | ||||
| 		if (debug) | ||||
| 		{ | ||||
| 			if (status == ERR_BADLANG && (BadLang_Table[make_string(pLangName)].last + 120.0f < gpGlobals->time)) | ||||
| 			{ | ||||
| 				AMXXLOG_Log("[AMXX] Language \"%s\" not found", pLangName); | ||||
| 				BadLang_Table[make_string(pLangName)].last = gpGlobals->time; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (addr[0] != LANG_SERVER) | ||||
| 			def = g_langMngr.GetDef(g_vault.get("server_language"), key, status); | ||||
| 		 | ||||
| 		if (!def && (strcmp(pLangName, "en") != 0 && strcmp(g_vault.get("server_language"), "en") != 0)) | ||||
| 			def = g_langMngr.GetDef("en", key, status); | ||||
| 	} | ||||
|  | ||||
| 	return def; | ||||
| } | ||||
|  | ||||
| #if defined AMD64 | ||||
| size_t do_amx_format_parameter(AMX *amx, cell *params, const char **fmtstr, int *param, char *output, size_t maxlen) | ||||
| { | ||||
| 	char fmt[32]; | ||||
| 	size_t len = 0; | ||||
| 	char *fmtptr = fmt; | ||||
| 	register const char *fmtsrc = *fmtstr; | ||||
| 	char ctrl_code; | ||||
| 	int numParams = params[0] / sizeof(cell); | ||||
| 	cell _addr, *addr; | ||||
|  | ||||
| 	*fmtptr++ = '%'; | ||||
| 	while (*fmtsrc && !isalpha(*fmtsrc)) | ||||
| 	{ | ||||
| 		if (len >= sizeof(fmt)-2) | ||||
| 			break; | ||||
| 		*fmtptr++ = static_cast<char>(*fmtsrc++); | ||||
| 		len++; | ||||
| 	} | ||||
|  | ||||
| 	//get the final character | ||||
| 	ctrl_code = *fmtsrc++; | ||||
| 	if (!ctrl_code) | ||||
| 		return 0; | ||||
| 	//inc the source pointer | ||||
| 	*fmtstr = fmtsrc; | ||||
| 	//finalize the string | ||||
| 	*fmtptr++ = ctrl_code; | ||||
| 	*fmtptr = '\0'; | ||||
| 	len = 0; | ||||
| 	//reset the format pointer | ||||
| 	fmtptr = fmt; | ||||
|  | ||||
| 	//we now have the format | ||||
| 	switch (ctrl_code) | ||||
| 	{ | ||||
| 	case 's': | ||||
| 		{ | ||||
| 			FMTPM_NEXTPARAM(); | ||||
| 			char buffer[2048]; | ||||
| 			get_amxstring_r(amx, _addr, buffer, 2047); | ||||
| 			return _snprintf(output, maxlen, fmtptr, buffer); | ||||
| 			break; | ||||
| 		} | ||||
| 	case 'g': | ||||
| 	case 'f': | ||||
| 		{ | ||||
| 			FMTPM_NEXTPARAM(); | ||||
| 			addr = get_amxaddr(amx, _addr); | ||||
| 			return _snprintf(output, maxlen, fmtptr, *(REAL *)addr); | ||||
| 			break; | ||||
| 		} | ||||
| 	case 'p': | ||||
| 		{ | ||||
| 			FMTPM_NEXTPARAM(); | ||||
| 			addr = get_amxaddr(amx, _addr); | ||||
| 			return _snprintf(output, maxlen, fmtptr, addr); | ||||
| 			break; | ||||
| 		} | ||||
| 	case 'x': | ||||
| 	case 'i': | ||||
| 	case 'd': | ||||
| 	case 'c': | ||||
| 		{ | ||||
| 			FMTPM_NEXTPARAM(); | ||||
| 			addr = get_amxaddr(amx, _addr); | ||||
| 			return _snprintf(output, maxlen, fmtptr, (int)addr[0]); | ||||
| 			break; | ||||
| 		} | ||||
| 	case 'L': | ||||
| 		{ | ||||
| 			FMTPM_NEXTPARAM(); | ||||
| 			cell lang_addr = _addr; | ||||
| 			FMTPM_NEXTPARAM(); | ||||
| 			int tmpLen; | ||||
| 			const char *key = get_amxstring(amx, _addr, 3, tmpLen); | ||||
|  | ||||
| 			const char *def = translate(amx, lang_addr, key); | ||||
|  | ||||
| 			if (!def) | ||||
| 				return _snprintf(output, maxlen, "ML_NOTFOUND: %s", key); | ||||
|  | ||||
| 			return do_amx_format(amx, params, param, &def, output, maxlen, 1); | ||||
| 		} | ||||
| 	default: | ||||
| 		{ | ||||
| 			return _snprintf(output, maxlen, "%s", fmtptr); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| //we implement this in raw asm for x86 | ||||
| //we'll do it for AMD64 once VAC2 works on it | ||||
| extern "C" size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output, size_t maxlen, int level) | ||||
| {	 | ||||
| 	size_t written; | ||||
| 	size_t orig_maxlen = maxlen; | ||||
| 	const char *save = *lex; | ||||
| 	register const char *lexptr = save; | ||||
|  | ||||
| 	while (*lexptr && maxlen) | ||||
| 	{ | ||||
| 		switch (*lexptr) | ||||
| 		{ | ||||
| 		case '%': | ||||
| 			{ | ||||
| 				lexptr++; | ||||
| 				if (*lexptr == '%' || *lexptr == '\0') | ||||
| 				{ | ||||
| 					*output++ = *lexptr++; | ||||
| 					*output++ = *lexptr++; | ||||
| 					maxlen -= 2; | ||||
| 				} else { | ||||
| 					written = do_amx_format_parameter(amx, params, &lexptr, param, output, maxlen); | ||||
| 					output += written; | ||||
| 					maxlen -= written; | ||||
| 				} | ||||
| 				break; | ||||
| 			} | ||||
| 		case '^': | ||||
| 			{ | ||||
| 				if (level) | ||||
| 				{ | ||||
| 					lexptr++; | ||||
| 					switch (*lexptr) | ||||
| 					{ | ||||
| 						case 'n': | ||||
| 						{ | ||||
| 							*output++ = '\n'; | ||||
| 							break; | ||||
| 						} | ||||
| 						case 't': | ||||
| 						{ | ||||
| 							*output++ = '\t'; | ||||
| 							break; | ||||
| 						} | ||||
| 						default: | ||||
| 						{ | ||||
| 							*output++ = *lexptr; | ||||
| 							break; | ||||
| 						} | ||||
| 					} | ||||
| 					lexptr++; | ||||
| 					maxlen--; | ||||
| 					break; | ||||
| 				} | ||||
| 			} | ||||
| 		default: | ||||
| 			{ | ||||
| 				*output++ = *lexptr++; | ||||
| 				maxlen--; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	*output = '\0'; | ||||
|  | ||||
| 	*lex = lexptr; | ||||
|  | ||||
| 	return (orig_maxlen-maxlen); | ||||
| } | ||||
| #endif | ||||
|  | ||||
| char * CLangMngr::FormatAmxString(AMX *amx, cell *params, int parm, int &len) | ||||
| { | ||||
| 	//do an initial run through all this  | ||||
| 	static char mystr[4096]; | ||||
| 	static char outbuf[4096]; | ||||
| 	const char *ptr = mystr; | ||||
| 	cell *addr = get_amxaddr(amx, params[parm++]); | ||||
|  | ||||
| 	get_amxstring_r(amx, params[parm++], mystr, sizeof(mystr)-1); | ||||
|  | ||||
| 	len = do_amx_format(amx, params, &parm, &ptr, outbuf, sizeof(outbuf)-1, 0); | ||||
| 	len = atcprintf(outbuf, sizeof(outbuf)-1, addr, amx, params, &parm); | ||||
|  | ||||
| 	return outbuf; | ||||
| } | ||||
|   | ||||
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										414
									
								
								amxmodx/format.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										414
									
								
								amxmodx/format.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,414 @@ | ||||
| #include "amxmodx.h" | ||||
| #include "format.h" | ||||
|  | ||||
| //Adapted from Quake3's snprintf | ||||
|  | ||||
| #define ALT			0x00000001		/* alternate form */ | ||||
| #define HEXPREFIX	0x00000002		/* add 0x or 0X prefix */ | ||||
| #define LADJUST		0x00000004		/* left adjustment */ | ||||
| #define LONGDBL		0x00000008		/* long double */ | ||||
| #define LONGINT		0x00000010		/* long integer */ | ||||
| #define QUADINT		0x00000020		/* quad integer */ | ||||
| #define SHORTINT	0x00000040		/* short integer */ | ||||
| #define ZEROPAD		0x00000080		/* zero (as opposed to blank) pad */ | ||||
| #define FPT			0x00000100		/* floating point number */ | ||||
| #define to_digit(c)		((c) - '0') | ||||
| #define is_digit(c)		((unsigned)to_digit(c) <= 9) | ||||
| #define to_char(n)		((n) + '0') | ||||
| #define CHECK_ARGS(n) \ | ||||
| 	if ((arg+n) > args) { \ | ||||
| 		LogError(amx, AMX_ERR_PARAMS, "String formatted incorrectly - parameter %d (total %d)", arg, args); \ | ||||
| 		return 0; \ | ||||
| 	} | ||||
|  | ||||
| THash<String, lang_err> BadLang_Table; | ||||
|  | ||||
| static cvar_t *amx_mldebug = NULL; | ||||
| static cvar_t *amx_cl_langs = NULL; | ||||
|  | ||||
| const char *translate(AMX *amx, cell amxaddr, const char *key) | ||||
| { | ||||
| 	const char *pLangName = NULL; | ||||
| 	const char *def = NULL; | ||||
| 	int status; | ||||
| 	cell *addr = get_amxaddr(amx, amxaddr); | ||||
| 	char name[4]; | ||||
| 	if (addr[0] == LANG_PLAYER) | ||||
| 	{ | ||||
| 		if (!amx_cl_langs) | ||||
| 			amx_cl_langs = CVAR_GET_POINTER("amx_client_languages"); | ||||
| 		if ( (int)amx_cl_langs->value == 0 ) | ||||
| 		{ | ||||
| 			pLangName = g_vault.get("server_language"); | ||||
| 		} else { | ||||
| 			pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(g_langMngr.GetDefLang())->pEdict, "lang"); | ||||
| 		} | ||||
| 	} else if (addr[0] == LANG_SERVER) { | ||||
| 		pLangName = g_vault.get("server_language"); | ||||
| 	} else if (addr[0] >= 1 && addr[0] <= gpGlobals->maxClients) { | ||||
| 		if (!amx_cl_langs) | ||||
| 			amx_cl_langs = CVAR_GET_POINTER("amx_client_languages"); | ||||
| 		if ( (int)amx_cl_langs->value == 0 ) | ||||
| 		{ | ||||
| 			pLangName = g_vault.get("server_language"); | ||||
| 		} else { | ||||
| 			pLangName = ENTITY_KEYVALUE(GET_PLAYER_POINTER_I(addr[0])->pEdict, "lang"); | ||||
| 		} | ||||
| 	} else { | ||||
| 		get_amxstring_r(amx, amxaddr, name, 3); | ||||
| 		pLangName = name; | ||||
| 	} | ||||
| 	if (!pLangName || !isalpha(pLangName[0])) | ||||
| 		pLangName = "en"; | ||||
| 	//next parameter! | ||||
| 	def = g_langMngr.GetDef(pLangName, key, status); | ||||
| 			 | ||||
| 	if (!amx_mldebug) | ||||
| 		amx_mldebug = CVAR_GET_POINTER("amx_mldebug"); | ||||
|  | ||||
| 	bool debug = (amx_mldebug && amx_mldebug->string && (amx_mldebug->string[0] != '\0')); | ||||
| 		 | ||||
| 	if (debug) | ||||
| 	{ | ||||
| 		int debug_status; | ||||
| 		bool validlang = true; | ||||
| 		const char *testlang = amx_mldebug->string; | ||||
| 		if (!g_langMngr.LangExists(testlang)) | ||||
| 		{ | ||||
| 			AMXXLOG_Log("[AMXX] \"%s\" is an invalid debug language", testlang); | ||||
| 			validlang = false; | ||||
| 		} | ||||
| 				 | ||||
| 		g_langMngr.GetDef(testlang, key, debug_status); | ||||
| 				 | ||||
| 		if (validlang && debug_status == ERR_BADKEY) | ||||
| 			AMXXLOG_Log("[AMXX] Language key \"%s\" not found for language \"%s\", check \"%s\"", key, testlang, GetFileName(amx)); | ||||
| 	} | ||||
| 				 | ||||
| 	if (def == NULL) | ||||
| 	{ | ||||
| 		if (debug) | ||||
| 		{ | ||||
| 			if (status == ERR_BADLANG && (BadLang_Table.AltFindOrInsert(pLangName).last + 120.0f < gpGlobals->time)) | ||||
| 			{ | ||||
| 				AMXXLOG_Log("[AMXX] Language \"%s\" not found", pLangName); | ||||
| 				BadLang_Table.AltFindOrInsert(pLangName).last = gpGlobals->time; | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
| 		if (addr[0] != LANG_SERVER) | ||||
| 			def = g_langMngr.GetDef(g_vault.get("server_language"), key, status); | ||||
| 		 | ||||
| 		if (!def && (strcmp(pLangName, "en") != 0 && strcmp(g_vault.get("server_language"), "en") != 0)) | ||||
| 			def = g_langMngr.GetDef("en", key, status); | ||||
| 	} | ||||
|  | ||||
| 	return def; | ||||
| } | ||||
|  | ||||
| template <typename U> | ||||
| void AddString(U **buf_p, size_t &maxlen, const cell *string, int width, int prec) | ||||
| { | ||||
| 	int		size = 0; | ||||
| 	U		*buf; | ||||
| 	static cell nlstr[] = {'(','n','u','l','l',')','\0'}; | ||||
|  | ||||
| 	buf = *buf_p; | ||||
|  | ||||
| 	if (string == NULL) | ||||
| 	{ | ||||
| 		string = nlstr; | ||||
| 		prec = -1; | ||||
| 	} | ||||
|  | ||||
| 	if (prec >= 0) | ||||
| 	{ | ||||
| 		for (size = 0; size < prec; size++)  | ||||
| 		{ | ||||
| 			if (string[size] == '\0') | ||||
| 				break; | ||||
| 		} | ||||
| 	} else { | ||||
| 		while (string[size++]) ; | ||||
| 		size--; | ||||
| 	} | ||||
|  | ||||
| 	if (size > (int)maxlen) | ||||
| 		size = maxlen; | ||||
|  | ||||
| 	maxlen -= size; | ||||
| 	width -= size; | ||||
|  | ||||
| 	while (size--) | ||||
| 		*buf++ = static_cast<U>(*string++); | ||||
|  | ||||
| 	while (width-- > 0 && maxlen) | ||||
| 	{ | ||||
| 		*buf++ = ' '; | ||||
| 		maxlen--; | ||||
| 	} | ||||
|  | ||||
| 	*buf_p = buf; | ||||
| } | ||||
|  | ||||
| template <typename U> | ||||
| void AddFloat(U **buf_p, size_t &maxlen, double fval, int width, int prec) | ||||
| { | ||||
| 	U		text[32]; | ||||
| 	int		digits; | ||||
| 	double	signedVal; | ||||
| 	U		*buf; | ||||
| 	int		val; | ||||
|  | ||||
| 	// get the sign | ||||
| 	signedVal = fval; | ||||
| 	if (fval < 0) | ||||
| 		fval = -fval; | ||||
|  | ||||
| 	// write the float number | ||||
| 	digits = 0; | ||||
| 	val = (int)fval; | ||||
| 	do { | ||||
| 		text[digits++] = '0' + val % 10; | ||||
| 		val /= 10; | ||||
| 	} while (val); | ||||
|  | ||||
| 	if (signedVal < 0) | ||||
| 		text[digits++] = '-'; | ||||
|  | ||||
| 	buf = *buf_p; | ||||
|  | ||||
| 	while (digits < width && maxlen) | ||||
| 	{ | ||||
| 		*buf++ = ' '; | ||||
| 		width--; | ||||
| 		maxlen--; | ||||
| 	} | ||||
|  | ||||
| 	while (digits-- && maxlen) | ||||
| 	{ | ||||
| 		*buf++ = text[digits]; | ||||
| 		maxlen--; | ||||
| 	} | ||||
|  | ||||
| 	*buf_p = buf; | ||||
|  | ||||
| 	if (prec < 0) | ||||
| 		prec = 6; | ||||
| 	// write the fraction | ||||
| 	digits = 0; | ||||
| 	while (digits < prec) | ||||
| 	{ | ||||
| 		fval -= (int) fval; | ||||
| 		fval *= 10.0; | ||||
| 		val = (int) fval; | ||||
| 		text[digits++] = '0' + val % 10; | ||||
| 	} | ||||
|  | ||||
| 	if (digits > 0 && maxlen) | ||||
| 	{ | ||||
| 		buf = *buf_p; | ||||
| 		*buf++ = '.'; | ||||
| 		maxlen--; | ||||
| 		for (prec = 0; maxlen && prec < digits; prec++) | ||||
| 		{ | ||||
| 			*buf++ = text[prec]; | ||||
| 			maxlen--; | ||||
| 		} | ||||
| 		*buf_p = buf; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| template <typename U> | ||||
| void AddInt(U **buf_p, size_t &maxlen, int val, int width, int flags) | ||||
| { | ||||
| 	U		text[32]; | ||||
| 	int		digits; | ||||
| 	int		signedVal; | ||||
| 	U		*buf; | ||||
|  | ||||
| 	digits = 0; | ||||
| 	signedVal = val; | ||||
| 	if (val < 0) | ||||
| 		val = -val; | ||||
| 	do { | ||||
| 		text[digits++] = '0' + val % 10; | ||||
| 		val /= 10; | ||||
| 	} while (val); | ||||
|  | ||||
| 	if (signedVal < 0) | ||||
| 		text[digits++] = '-'; | ||||
|  | ||||
| 	buf = *buf_p; | ||||
|  | ||||
| 	if( !(flags & LADJUST) ) | ||||
| 	{ | ||||
| 		while (digits < width && maxlen) | ||||
| 		{ | ||||
| 			*buf++ = (flags & ZEROPAD) ? '0' : ' '; | ||||
| 			width--; | ||||
| 			maxlen--; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	while (digits-- && maxlen) | ||||
| 	{ | ||||
| 		*buf++ = text[digits]; | ||||
| 		width--; | ||||
| 		maxlen--; | ||||
| 	} | ||||
|  | ||||
| 	if (flags & LADJUST) | ||||
| 	{ | ||||
| 		while (width-- && maxlen) | ||||
| 		{ | ||||
| 			*buf++ = (flags & ZEROPAD) ? '0' : ' '; | ||||
| 			maxlen--; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	*buf_p = buf; | ||||
| } | ||||
|  | ||||
| template <typename D, typename S> | ||||
| size_t atcprintf(D *buffer, size_t maxlen, const S *format, AMX *amx, cell *params, int *param) | ||||
| { | ||||
| 	int		arg; | ||||
| 	int		args = params[0] / sizeof(cell); | ||||
| 	D		*buf_p; | ||||
| 	D		ch; | ||||
| 	int		flags; | ||||
| 	int		width; | ||||
| 	int		prec; | ||||
| 	int		n; | ||||
| 	char	sign; | ||||
| 	const S	*fmt; | ||||
| 	size_t	llen = maxlen; | ||||
|  | ||||
| 	buf_p = buffer; | ||||
| 	arg = *param; | ||||
| 	fmt = format; | ||||
|  | ||||
| 	while (true) | ||||
| 	{ | ||||
| 		// run through the format string until we hit a '%' or '\0' | ||||
| 		for (ch = static_cast<D>(*fmt);  | ||||
| 			llen && ((ch = static_cast<D>(*fmt)) != '\0' && ch != '%'); | ||||
| 			fmt++) | ||||
| 		{ | ||||
| 			*buf_p++ = static_cast<D>(ch); | ||||
| 			llen--; | ||||
| 		} | ||||
| 		if (ch == '\0' || llen <= 0) | ||||
| 			goto done; | ||||
|  | ||||
| 		// skip over the '%' | ||||
| 		fmt++; | ||||
|  | ||||
| 		// reset formatting state | ||||
| 		flags = 0; | ||||
| 		width = 0; | ||||
| 		prec = -1; | ||||
| 		sign = '\0'; | ||||
|  | ||||
| rflag: | ||||
| 		ch = static_cast<D>(*fmt++); | ||||
| reswitch: | ||||
| 		switch(ch) | ||||
| 		{ | ||||
| 		case '-': | ||||
| 			flags |= LADJUST; | ||||
| 			goto rflag; | ||||
| 		case '.': | ||||
| 			n = 0; | ||||
| 			while( is_digit( ( ch = static_cast<D>(*fmt++)) ) ) | ||||
| 				n = 10 * n + ( ch - '0' ); | ||||
| 			prec = n < 0 ? -1 : n; | ||||
| 			goto reswitch; | ||||
| 		case '0': | ||||
| 			flags |= ZEROPAD; | ||||
| 			goto rflag; | ||||
| 		case '1': | ||||
| 		case '2': | ||||
| 		case '3': | ||||
| 		case '4': | ||||
| 		case '5': | ||||
| 		case '6': | ||||
| 		case '7': | ||||
| 		case '8': | ||||
| 		case '9': | ||||
| 			n = 0; | ||||
| 			do { | ||||
| 				n = 10 * n + ( ch - '0' ); | ||||
| 				ch = static_cast<D>(*fmt++); | ||||
| 			} while( is_digit( ch ) ); | ||||
| 			width = n; | ||||
| 			goto reswitch; | ||||
| 		case 'c': | ||||
| 			CHECK_ARGS(0); | ||||
| 			*buf_p++ = static_cast<D>(*get_amxaddr(amx, params[arg])); | ||||
| 			arg++; | ||||
| 			break; | ||||
| 		case 'd': | ||||
| 		case 'i': | ||||
| 			CHECK_ARGS(0); | ||||
| 			AddInt(&buf_p, llen, *get_amxaddr(amx, params[arg]), width, flags); | ||||
| 			arg++; | ||||
| 			break; | ||||
| 		case 'f': | ||||
| 			CHECK_ARGS(0); | ||||
| 			AddFloat(&buf_p, llen, amx_ctof(*get_amxaddr(amx, params[arg])), width, prec); | ||||
| 			arg++; | ||||
| 			break; | ||||
| 		case 's': | ||||
| 			CHECK_ARGS(0); | ||||
| 			AddString(&buf_p, llen, get_amxaddr(amx, params[arg]), width, prec); | ||||
| 			arg++; | ||||
| 			break; | ||||
| 		case 'L': | ||||
| 			{ | ||||
| 				CHECK_ARGS(1); | ||||
| 				cell addr = params[arg++]; | ||||
| 				int len; | ||||
| 				const char *key = get_amxstring(amx, params[arg++], 3, len); | ||||
| 				const char *def = translate(amx, addr, key); | ||||
| 				size_t written = atcprintf(buf_p, llen, def, amx, params, &arg); | ||||
| 				buf_p += written; | ||||
| 				maxlen -= written; | ||||
| 				break; | ||||
| 			} | ||||
| 		case '%': | ||||
| 			*buf_p++ = static_cast<D>(ch); | ||||
| 			break; | ||||
| 		case '\0': | ||||
| 			*buf_p++ = static_cast<D>('%'); | ||||
| 			goto done; | ||||
| 			break; | ||||
| 		default: | ||||
| 			*buf_p++ = static_cast<D>(ch); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| done: | ||||
| 	*buf_p = static_cast<D>(0); | ||||
| 	*param = arg; | ||||
| 	return maxlen-llen; | ||||
| } | ||||
|  | ||||
| /** | ||||
|  * HACKHACK: The compiler will generate code for each case we need. | ||||
|  * Don't remove this, otherwise files that use certain code generations | ||||
|  *  will have extern problems.  For each case you need, add dummy code | ||||
|  *  here. | ||||
|  */ | ||||
| void __WHOA_DONT_CALL_ME_PLZ_K_lol_o_O() | ||||
| { | ||||
| 	//acsprintf | ||||
| 	atcprintf((cell *)NULL, 0, (const char *)NULL, NULL, NULL, NULL); | ||||
| 	//accprintf | ||||
| 	atcprintf((cell *)NULL, 0, (cell *)NULL, NULL, NULL, NULL); | ||||
| 	//acsprintf | ||||
| 	atcprintf((char *)NULL, 0, (cell *)NULL, NULL, NULL, NULL); | ||||
| } | ||||
|  | ||||
							
								
								
									
										8
									
								
								amxmodx/format.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								amxmodx/format.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #ifndef _INCLUDE_FORMATTING_H | ||||
| #define _INCLUDE_FORMATTING_H | ||||
|  | ||||
| //Amx Templatized Cell Printf | ||||
| template <typename D, typename S> | ||||
| size_t atcprintf(D *buffer, size_t maxlen, const S *format, AMX *amx, cell *params, int *param); | ||||
|  | ||||
| #endif //_INCLUDE_FORMATTING_H | ||||
| @@ -1,424 +0,0 @@ | ||||
| ;(C)2004-2006 AMX Mod X Development Team | ||||
| ;Written by David "BAILOPAN" Anderson | ||||
| ;These routines were very hard to optimize.   | ||||
| ;They are basically unoptimizable as far as I can tell, | ||||
| ; but it's one of the most expensive operations in core. | ||||
|  | ||||
|  | ||||
| section .text | ||||
|  | ||||
| %ifdef LINUX | ||||
| %define __snprintf snprintf | ||||
| %define _get_amxstring_r get_amxstring_r | ||||
| %define _MNF_GetAmxString MNF_GetAmxString | ||||
| %define _translate translate | ||||
| %define _LogError LogError | ||||
| %endif | ||||
|  | ||||
| extern _LogError, _get_amxstring_r, __snprintf, _MNF_GetAmxString | ||||
| extern _translate | ||||
|  | ||||
| global do_amx_format, _do_amx_format, format_parameter | ||||
| global init_format_jumps, _init_format_jumps | ||||
|  | ||||
| init_format_jumps: | ||||
| _init_format_jumps: | ||||
| 	push	ebp | ||||
| 	mov	ebp, esp | ||||
| 	 | ||||
| 	lea	edx, [g_jumptbl] | ||||
| 	mov	[edx+'c'*4], dword format_parameter.fmt_num | ||||
| 	mov	[edx+'d'*4], dword format_parameter.fmt_num | ||||
| 	mov	[edx+'f'*4], dword format_parameter.fmt_float | ||||
| 	mov	[edx+'g'*4], dword format_parameter.fmt_float | ||||
| 	mov	[edx+'i'*4], dword format_parameter.fmt_num | ||||
| 	mov	[edx+'L'*4], dword format_parameter.fmt_ml | ||||
| 	;mov	[edx+'p'*4], dword format_parameter.fmt_ptr | ||||
| 	mov	[edx+'s'*4], dword format_parameter.fmt_string | ||||
| 	mov	[edx+'x'*4], dword format_parameter.fmt_num | ||||
|  | ||||
| 	pop	ebp | ||||
| 	ret | ||||
| 	 | ||||
|  | ||||
| ;size_t do_amx_format_parameter(AMX *amx, cell *params, int *param, size_t maxlen); | ||||
| ;REGISTER USAGE (fmt search) | ||||
| ;  edi - fmt output | ||||
| ;  esi - lexptr (given) | ||||
| ;  ebx - scrach address | ||||
| ;  eax - lexchar | ||||
| ;  edx - scratch | ||||
| ;  ecx - length | ||||
| ;REGISTER USAGE (format) | ||||
| ;  edi - real output | ||||
| ;  esi - lexptr (given) | ||||
| format_parameter: | ||||
| 	push	ebp | ||||
| 	mov	ebp, esp | ||||
| 	 | ||||
| 	push	edi | ||||
| 	push	ebx | ||||
| 	push	esi | ||||
| 	 | ||||
| 	;len=30 | ||||
| 	mov	ecx, 30 | ||||
| 	;edi=char[32] (+1 for offset) | ||||
| 	sub	esp, 32 | ||||
| 	mov	[esp], byte '%' | ||||
| 	lea	edi, [esp+1] | ||||
| 	;esi=lexptr already | ||||
| 	;eax=*lexptr | ||||
| 	xor	eax, eax | ||||
| 	mov	al, [esi] | ||||
| 	test	al, al | ||||
| 	jz	.abort | ||||
| 	;ebx=g_chartbl | ||||
| 	lea	ebx, [g_chartbl] | ||||
| 	;start looping | ||||
| .fmtloop | ||||
| 	mov	edx, [ebx+eax*4] ;get char flag | ||||
| 	test	edx, edx	;is it zero? | ||||
| 	jnz	.fmtdone	;yes, we've got a format code | ||||
| 	test	ecx, ecx	;are we over maxlen? | ||||
| 	jz	.fmtdone	;yes, dump out | ||||
| 	mov	[edi], al	;copy into destination | ||||
| 	inc	edi		;dest++ | ||||
| 	inc	esi		;src++ | ||||
| 	dec	ecx		;len-- | ||||
| 	mov	al, [esi]	;get next char | ||||
| 	test	al, al		;is it zero? | ||||
| 	jnz	.fmtloop	;no, continue | ||||
| 	 | ||||
| .fmtdone: | ||||
| 	;if there's no control code, we dumped out. | ||||
| 	;just abort in that case. | ||||
| 	test	al, al | ||||
| 	jz	.abort | ||||
| 	;terminate fmtptr | ||||
| 	mov	[edi], al | ||||
| 	mov	[edi+1], byte 0 | ||||
| 	;sto fmtsrc back | ||||
| 	inc	esi | ||||
| 	;get output ptr | ||||
| 	mov	edi, [ebp-4] | ||||
| 	mov	edx, [ebp-12] | ||||
| 	lea	ebx, [g_jumptbl] | ||||
| 	jmp	[ebx+eax*4]	;LOLolOLoL. | ||||
| 	 | ||||
| .fmt_string | ||||
| 	;check parameter count | ||||
| 	mov	ebx, [ebp+12]	;params | ||||
| 	mov	eax, [ebx]	;params[0] | ||||
| 	shr	eax, 2		;params[0]/4 | ||||
| 	mov	edx, [ebp+16]	;param | ||||
| 	mov	ecx, [edx]	;*param | ||||
| 	cmp	ecx, eax	;*param / params[0]/4 ? | ||||
| 	ja	.error | ||||
| 	;get the param - it's in eax | ||||
| 	add	dword [edx], 1 | ||||
| 	mov	eax, ebx | ||||
| 	sub	esp, 2048 | ||||
| 	mov	ebx, esp | ||||
| 	push	2047		;buffer size | ||||
| 	push	ebx | ||||
| 	push	dword [eax+ecx*4] | ||||
| 	push	dword [ebp+8]	;context | ||||
| 	call	_get_amxstring_r | ||||
| 	push	ebx		;push buffer | ||||
| 	lea	ebx, [ebp-44] | ||||
| 	push	ebx		;push format | ||||
| 	push	dword [ebp+28]	;push maxlen | ||||
| 	push	edi		;push output | ||||
| 	call	__snprintf | ||||
| 	add	esp, 4*8 | ||||
| 	add	esp, 2048 | ||||
| 	add	edi, eax | ||||
| 	jmp	.end | ||||
| 	 | ||||
| .fmt_num | ||||
| 	;check parameter count | ||||
| 	mov	ebx, [ebp+12]		;params | ||||
| 	mov	eax, [ebx]		;params[0] | ||||
| 	shr	eax, 2			;params[0]/4 | ||||
| 	mov	edx, [ebp+16]		;param | ||||
| 	mov	ecx, [edx]		;*param | ||||
| 	cmp	ecx, eax		;*param / params[0]/4 ? | ||||
| 	ja	.error | ||||
| 	;get the param - it's in eax | ||||
| 	add	dword [edx], 1		;incr *param | ||||
| 	mov	edx, [ebp+8]		;get AMX into edx | ||||
| 	mov	edx, [edx]		;get AMX->base into edx | ||||
| 	mov	eax, [edx+16]		;get base->dat into eax | ||||
| 	add	edx, eax		;add dat to base | ||||
| 	add	edx, dword [ebx+ecx*4]	;add params[ecx] | ||||
| 	push	dword [edx] | ||||
| 	lea	ebx, [ebp-44] | ||||
| 	push	ebx | ||||
| 	push	dword [ebp+28] | ||||
| 	push	edi | ||||
| 	call	__snprintf | ||||
| 	add	esp, 4*4 | ||||
| 	add	edi, eax | ||||
| 	jmp	.end | ||||
| 	 | ||||
| .fmt_float | ||||
| 	;check parameter count | ||||
| 	mov	ebx, [ebp+12]	;params | ||||
| 	mov	eax, [ebx]	;params[0] | ||||
| 	shr	eax, 2		;params[0]/4 | ||||
| 	mov	edx, [ebp+16]	;param | ||||
| 	mov	ecx, [edx]	;*param | ||||
| 	cmp	ecx, eax	;*param / params[0]/4 ? | ||||
| 	ja	.error | ||||
| 	;get the param - it's in eax | ||||
| 	add	dword [edx], 1 | ||||
| 	mov	edx, [ebp+8] | ||||
| 	mov	edx, [edx] | ||||
| 	mov	eax, [edx+16] | ||||
| 	add	edx, eax | ||||
| 	add	edx, dword [ebx+ecx*4] | ||||
| 	;load the float, convert to double | ||||
| 	fld	dword [edx] | ||||
| 	sub	esp, 8 | ||||
| 	fstp	qword [esp] | ||||
| 	;it's already on the stack now, push rest | ||||
| 	lea	ebx, [ebp-44] | ||||
| 	push	ebx | ||||
| 	push	dword [ebp+28] | ||||
| 	push	edi | ||||
| 	call	__snprintf | ||||
| 	add	esp, 4*5 | ||||
| 	add	edi, eax | ||||
| 	jmp	.end | ||||
| 	 | ||||
| .fmt_ml | ||||
| 	mov	ebx, [ebp+12]	;params | ||||
| 	mov	eax, [ebx]	;params[0] | ||||
| 	shr	eax, 2		;params[0]/4 | ||||
| 	mov	edx, [ebp+16]	;param | ||||
| 	mov	ecx, [edx]	;*param | ||||
| 	inc	ecx | ||||
| 	cmp	ecx, eax	;*param / params[0]/4 ? | ||||
| 	ja	.error | ||||
| 	add	dword [edx], 2 | ||||
| 	push	ecx | ||||
| 	push	dword 0		;NULL | ||||
| 	push	dword 3		;buffer 3 | ||||
| 	push	dword [ebx+ecx*4] | ||||
| 	push	dword [ebp+8] | ||||
| 	call	_MNF_GetAmxString | ||||
| 	add	esp, 4*4 | ||||
| 	pop	ecx | ||||
| 	dec	ecx | ||||
| 	push	eax | ||||
| 	push	eax			;key | ||||
| 	push	dword [ebx+ecx*4]	;lang_addr | ||||
| 	push	dword [ebp+8]		;AMX | ||||
| 	call	_translate | ||||
| 	add	esp, 4*3 | ||||
| 	pop	ecx | ||||
| 	test	eax, eax | ||||
| 	je	.fmt_error | ||||
| 	 | ||||
| 	;invoke the translator | ||||
| 	;;store this on the stack so we can pass the address | ||||
| 	push	eax | ||||
| 	mov	edx, esp | ||||
| 	push	1			;no reparse ^ | ||||
| 	push	dword [ebp+20]		;maxlen | ||||
| 	push	edi			;output | ||||
| 	push	edx			;lexptr | ||||
| 	push	dword [ebp+16]		;param | ||||
| 	push	ebx			;params | ||||
| 	push	dword [ebp+8]		;amx | ||||
| 	call	do_amx_format | ||||
| 	add	esp, 4*8 | ||||
| 	;we don't care about the return lex | ||||
| 	add	edi, eax | ||||
| 	jmp	.end | ||||
| 	 | ||||
| 	 | ||||
| .fmt_error | ||||
| 	push	ecx | ||||
| 	lea	eax, [g_mlfmt] | ||||
| 	push	eax | ||||
| 	push	dword [ebp+20] | ||||
| 	push 	edi | ||||
| 	call	__snprintf | ||||
| 	add	esp, 4*4 | ||||
| 	add	edi, eax | ||||
| 	jmp	.end | ||||
| 	 | ||||
| 	 | ||||
| .fmt_default | ||||
| 	mov	esi, edx | ||||
| 	;store the % at least | ||||
| 	mov	[edi], byte '%' | ||||
| 	inc 	edi | ||||
| 	mov	eax, 1 | ||||
| 	jmp	.end	 | ||||
|  | ||||
| .error | ||||
| 	push	ecx | ||||
| 	push	eax | ||||
| 	push	g_errfmt | ||||
| 	push	10	;AMX_ERR_NATIVE | ||||
| 	push	dword [ebp+8] | ||||
| 	call 	_LogError | ||||
| 	add	esp, 4*5 | ||||
|  | ||||
| .abort | ||||
| 	xor	eax, eax | ||||
|  | ||||
| .end | ||||
| 	add	esp, 32 | ||||
| 	pop	ecx | ||||
| 	pop	ebx | ||||
| 	pop	ecx | ||||
| 	 | ||||
| 	pop	ebp | ||||
| 	ret | ||||
|  | ||||
| ;size_t do_amx_format(AMX *amx, cell *params, int *param, const char **lex, char *output, size_t maxlen, int level) | ||||
| ;REGISTER USAGE -  | ||||
| ;    esi=lex | ||||
| ;    edi=output | ||||
| ;    ecx=maxlen | ||||
| ;    eax=scratch | ||||
| do_amx_format: | ||||
| _do_amx_format: | ||||
| 	push	esi				;input | ||||
| 	push	edi				;output | ||||
| 	 | ||||
| 	;current esp offset is 12 (0=edi,4=esi,8=ret) | ||||
| 	mov	esi, [esp+24]	;lex (dbl addr) | ||||
| 	mov	esi, [esi] | ||||
| 	mov	edi, [esp+28]	;get output | ||||
| 	mov	ecx, [esp+32]	;get maxlen | ||||
|  | ||||
| 	;initial checks | ||||
| 	mov	al, [esi] | ||||
| 	test	al, al | ||||
| 	jz	.done | ||||
| .loop: | ||||
| 	test	ecx, ecx | ||||
| 	jz 	.done | ||||
| 	cmp	al, '%' | ||||
| 	je	.perc | ||||
| 	cmp	al, '^' | ||||
| 	je	.esc | ||||
| 	 | ||||
| .copy: | ||||
| 	;*output++ = *lexptr++ | ||||
| 	mov	[edi], al | ||||
| 	inc	esi | ||||
| 	inc	edi | ||||
| 	dec	ecx | ||||
| .next | ||||
| 	mov	al, [esi] | ||||
| 	test	al, al | ||||
| 	jnz	.loop | ||||
| 	jmp	.done | ||||
|  | ||||
| ;we got a '^' | ||||
| .esc: | ||||
| 	cmp	dword [esp+36], 0 | ||||
| 	je	.copy | ||||
| 	inc	esi | ||||
| 	mov	al, [esi] | ||||
| 	cmp	al, 'n' | ||||
| 	je	.escn | ||||
| 	cmp	al, 't' | ||||
| 	je	.esct | ||||
|  | ||||
| ;*outptr++ = *lexptr | ||||
| 	mov	[edi], al | ||||
| 	inc	edi | ||||
|  | ||||
| ;lexptr++ | ||||
| ;maxlen-- | ||||
| .escdone | ||||
| 	inc	esi | ||||
| 	dec	ecx | ||||
| 	jmp	.next | ||||
|  | ||||
| .escn | ||||
| 	;*outptr++ = '\n' | ||||
| 	mov	[edi], byte 0xA	;'\n' | ||||
| 	inc	edi | ||||
| 	jmp	.escdone | ||||
| 	 | ||||
| .esct | ||||
| 	;*outptr++ = '\t' | ||||
| 	mov	[edi], byte 0x9	;'\t' | ||||
| 	inc	edi | ||||
| 	jmp	.escdone | ||||
|  | ||||
| ;we got a '%' | ||||
| .perc: | ||||
| 	inc	esi | ||||
| 	mov	al, [esi]	 | ||||
| 	test	al, al		;'\0' | ||||
| 	je	.percatend | ||||
| 	cmp	al, '%'	 | ||||
| 	je	.percnone | ||||
| 	jmp	.percfmt | ||||
| .percatend | ||||
| 	dec	esi | ||||
| 	add	ecx, 1 | ||||
| .percnone: | ||||
| 	;*outptr++=*lexptr++; x2 | ||||
| 	;maxlen -= 2 | ||||
| 	;note we recalculate eax and then | ||||
| 	;only move once, since this is a 2byte move anyway. | ||||
| 	mov	ax, [esi] | ||||
| 	mov	[edi], ax | ||||
| 	add	esi, 2 | ||||
| 	add	edi, 2 | ||||
| 	sub	ecx, 2 | ||||
| 	jmp	.next | ||||
| 	 | ||||
| .percfmt: | ||||
| 	;call do_amx_format_parameter. | ||||
| 	push	ecx | ||||
| 	push	ecx		;maxlen | ||||
| 	push	dword [esp+28]	;param | ||||
| 	push	dword [esp+28]	;params | ||||
| 	push	dword [esp+28]	;amx | ||||
| 	call	format_parameter	;will return edi adjusted for us | ||||
| 	add	esp, 4*4	;will also return esi adjusted for us | ||||
| 	pop	ecx | ||||
| 	sub	ecx, eax	;adjust maxlength | ||||
| 	mov	al, [esi]	;reiterate | ||||
| 	test	al, al | ||||
| 	jnz	.loop | ||||
| 	 | ||||
| .done: | ||||
| 	;end the string | ||||
| 	mov	[edi], dword 0 | ||||
| 	mov	edi, [esp+24]	;get lexptr ref | ||||
| 	mov	[edi], esi	;sto into lexptr ref | ||||
| 	mov	eax, [esp+32]	;get maxlen | ||||
| 	sub	eax, ecx	;subtract what we did | ||||
| 	 | ||||
| 	pop	edi | ||||
| 	pop	esi | ||||
| 	 | ||||
| 	ret | ||||
|  | ||||
|  | ||||
| section .data | ||||
| 	align 16 | ||||
| 	g_errfmt	db "String formatted incorrectly - parameter %d (total %d)", 0 | ||||
| 	g_mlfmt		db "ML_NOTFOUND: %s", 0 | ||||
| 	;Stores whether a character is a letter or not.  hAxXx | ||||
| 	g_chartbl	times  65 dd 0 | ||||
| 			times  26 dd 1 | ||||
| 			times   6 dd 0 | ||||
| 			times  26 dd 1 | ||||
| 			times 133 dd 0 | ||||
| 					 | ||||
| 	g_jumptbl	times 256 dd format_parameter.fmt_default | ||||
| 					 | ||||
| ;end | ||||
|  | ||||
| @@ -1145,14 +1145,6 @@ C_DLLEXPORT	int	Meta_Query(char	*ifvers, plugin_info_t **pPlugInfo,	mutil_funcs_ | ||||
| 	return (TRUE); | ||||
| } | ||||
|  | ||||
| #if !defined AMD64 | ||||
| extern "C" void init_format_jumps(); | ||||
| #else | ||||
| void init_format_jumps() | ||||
| { | ||||
| } | ||||
| #endif | ||||
|  | ||||
| static META_FUNCTIONS gMetaFunctionTable; | ||||
| C_DLLEXPORT	int	Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, meta_globals_t *pMGlobals, gamedll_funcs_t *pGamedllFuncs) | ||||
| { | ||||
| @@ -1231,8 +1223,6 @@ C_DLLEXPORT	int	Meta_Attach(PLUG_LOADTIME now, META_FUNCTIONS *pFunctionTable, m | ||||
| 	// This will also call modules Meta_Query and Meta_Attach functions | ||||
| 	loadModules(get_localinfo("amxx_modules", "addons/amxmodx/configs/modules.ini"), now); | ||||
|  | ||||
| 	init_format_jumps(); | ||||
|  | ||||
| 	return (TRUE); | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -303,7 +303,7 @@ | ||||
| 			<Tool | ||||
| 				Name="VCCLCompilerTool" | ||||
| 				Optimization="0" | ||||
| 				AdditionalIncludeDirectories=""C:\Hry\Half-Life\SDK\Multiplayer Source\pm_shared";"C:\Hry\Half-Life\SDK\Multiplayer Source\dlls";"C:\Hry\Half-Life\SDK\Multiplayer Source\engine";"C:\Hry\Half-Life\SDK\Multiplayer Source\common";C:\Files\Programming\metamod\metamod" | ||||
| 				AdditionalIncludeDirectories="" | ||||
| 				PreprocessorDefinitions="WIN32;_DEBUG;_WINDOWS;_USRDLL;amxmodx_EXPORTS;PAWN_CELL_SIZE=32;ASM32;JIT" | ||||
| 				BasicRuntimeChecks="3" | ||||
| 				RuntimeLibrary="5" | ||||
| @@ -671,6 +671,15 @@ | ||||
| 			<File | ||||
| 				RelativePath="..\float.cpp"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\format.cpp"> | ||||
| 				<FileConfiguration | ||||
| 					Name="JITRelease|Win32"> | ||||
| 					<Tool | ||||
| 						Name="VCCLCompilerTool" | ||||
| 						AssemblerOutput="4"/> | ||||
| 				</FileConfiguration> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\md5.cpp"> | ||||
| 			</File> | ||||
| @@ -823,6 +832,9 @@ | ||||
| 			<File | ||||
| 				RelativePath="..\fakemeta.h"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\format.h"> | ||||
| 			</File> | ||||
| 			<File | ||||
| 				RelativePath="..\md5.h"> | ||||
| 			</File> | ||||
| @@ -957,13 +969,6 @@ | ||||
| 				RelativePath="..\sdk\moduleconfig.h"> | ||||
| 			</File> | ||||
| 		</Filter> | ||||
| 		<Filter | ||||
| 			Name="Helpers" | ||||
| 			Filter=""> | ||||
| 			<File | ||||
| 				RelativePath="..\Jit\helpers-x86.obj"> | ||||
| 			</File> | ||||
| 		</Filter> | ||||
| 	</Files> | ||||
| 	<Globals> | ||||
| 	</Globals> | ||||
|   | ||||
| @@ -31,6 +31,7 @@ | ||||
|  | ||||
| #include <ctype.h> | ||||
| #include "amxmodx.h" | ||||
| #include "format.h" | ||||
|  | ||||
| const char* stristr(const char* str, const char* substr) | ||||
| { | ||||
| @@ -463,8 +464,14 @@ static cell AMX_NATIVE_CALL equali(AMX *amx, cell *params) /* 3 param */ | ||||
|  | ||||
| static cell AMX_NATIVE_CALL format(AMX *amx, cell *params) /* 3 param */ | ||||
| { | ||||
| 	int len; | ||||
| 	return set_amxstring(amx, params[1], format_amxstring(amx, params, 3, len), params[2]); | ||||
| 	//int len; | ||||
| 	//return set_amxstring(amx, params[1], format_amxstring(amx, params, 3, len), params[2]); | ||||
| 	cell *buf = get_amxaddr(amx, params[1]); | ||||
| 	cell *fmt = get_amxaddr(amx, params[3]); | ||||
| 	size_t maxlen = params[2]; | ||||
| 	int param = 4; | ||||
| 	size_t total = atcprintf(buf, maxlen, fmt, amx, params, ¶m); | ||||
| 	return total; | ||||
| } | ||||
|  | ||||
| static cell AMX_NATIVE_CALL parse(AMX *amx, cell *params) /* 3 param */ | ||||
|   | ||||
		Reference in New Issue
	
	Block a user