Revert "Merge branch 'master' of github.com:pawn-lang/compiler into HEAD"

This reverts commit 5400511d8616964ddf2c78bb65e72dfc23fa3a25, reversing
changes made to 2e15e645e687bc0ad4a210963de0bfadc56d48fc.
This commit is contained in:
Y_Less 2018-10-30 22:51:21 +01:00
parent 5400511d86
commit c565a5d1df
17 changed files with 660 additions and 2698 deletions

View File

@ -27,63 +27,54 @@
#include <stdlib.h> /* for size_t */
#include <limits.h>
#if (defined __linux || defined __linux__) && !defined __LINUX__
#define __LINUX__
#endif
#if defined FREEBSD && !defined __FreeBSD__
#define __FreeBSD__
#endif
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__
#include <sclinux.h>
#endif
#if defined __GNUC__
#define GCC_VERSION (__GNUC__ * 10000 \
+ __GNUC_MINOR__ * 100 \
+ __GNUC_PATCHLEVEL__)
#endif
#if !defined HAVE_STDINT_H
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L) \
|| defined __GNUC__ || defined __LCC__ || defined __DMC__ \
|| (defined __WATCOMC__ && __WATCOMC__ >= 1200)
#define HAVE_STDINT_H 1
#endif
#endif
#if !defined HAVE_INTTYPES_H
#if defined __FreeBSD__ || defined __APPLE__
#define HAVE_INTTYPES_H 1
#endif
#endif
#if defined HAVE_STDINT_H
#include <stdint.h>
#elif defined HAVE_INTTYPES_H
#include <inttypes.h>
#else
#if defined __MACH__
#include <ppc/types.h>
#endif
typedef short int int16_t;
typedef unsigned short int uint16_t;
#if defined SN_TARGET_PS2
typedef int int32_t;
typedef unsigned int uint32_t;
#else
typedef long int int32_t;
typedef unsigned long int uint32_t;
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define HAVE_I64
#endif
#if !defined _INTPTR_T_DEFINED
#if defined _LP64 || defined WIN64 || defined _WIN64
typedef __int64 intptr_t;
#if defined __LCC__ || defined __DMC__ || defined LINUX || (defined __WATCOMC__ && __WATCOMC__ >= 1200)
#if defined HAVE_INTTYPES_H
#include <inttypes.h>
#else
typedef int32_t intptr_t;
#include <stdint.h>
#endif
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
/* The ISO C99 defines the int16_t and int_32t types. If the compiler got
* here, these types are probably undefined.
*/
#if defined __MACH__
#include <ppc/types.h>
typedef unsigned short int uint16_t;
typedef unsigned long int uint32_t;
#elif defined __FreeBSD__
#include <inttypes.h>
#else
typedef short int int16_t;
typedef unsigned short int uint16_t;
#if defined SN_TARGET_PS2
typedef int int32_t;
typedef unsigned int uint32_t;
#else
typedef long int int32_t;
typedef unsigned long int uint32_t;
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32
typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#define HAVE_I64
#elif defined __GNUC__
typedef long long int64_t;
typedef unsigned long long uint64_t;
#define HAVE_I64
#endif
#endif
#endif
#define HAVE_STDINT_H
#endif
#if defined _LP64 || defined WIN64 || defined _WIN64
#if !defined __64BIT__
@ -91,17 +82,8 @@
#endif
#endif
#if !defined HAVE_ALLOCA_H
#if defined __GNUC__ || defined __LCC__ || defined __DMC__ || defined __ARMCC_VERSION
#define HAVE_ALLOCA_H 1
#elif defined __WATCOMC__ && __WATCOMC__ >= 1200
#define HAVE_ALLOCA_H 1
#endif
#endif
#if defined HAVE_ALLOCA_H && HAVE_ALLOCA_H
#if HAVE_ALLOCA_H
#include <alloca.h>
#elif defined __BORLANDC__
#include <malloc.h>
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32 /* || defined __MSDOS__ */
#if !defined alloca
@ -112,21 +94,14 @@
#if !defined arraysize
#define arraysize(array) (sizeof(array) / sizeof((array)[0]))
#endif
#if !defined assert_static
#if (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112) || GCC_VERSION >= 40600
#define assert_static(test) _Static_assert(test, "assert")
#else
/* see "Compile-Time Assertions" by Greg Miller,
* (with modifications to port it to C)
*/
#define _ASSERT_STATIC_SYMBOL_INNER(line) __ASSERT_STATIC_ ## line
#define _ASSERT_STATIC_SYMBOL(line) _ASSERT_STATIC_SYMBOL_INNER(line)
#define assert_static(test) \
do { \
typedef char _ASSERT_STATIC_SYMBOL(__LINE__)[ ((test) ? 1 : -1) ]; \
} while (0)
#endif
/* see "Compile-Time Assertions" by Ralf Holly,
* C/C++ Users Journal, November 2004
*/
#define assert_static(e) \
do { \
enum { assert_static__ = 1/(e) }; \
} while (0)
#endif
#ifdef __cplusplus
@ -217,14 +192,9 @@ typedef int (AMXAPI *AMX_IDLE)(struct tagAMX *amx, int AMXAPI Exec(struct tagAMX
#endif
#if defined _MSC_VER
#pragma warning(disable:4103) /* disable warning message 4103 that complains
* about pragma pack in a header file */
#pragma warning(disable:4100) /* "'%$S' : unreferenced formal parameter" */
#pragma warning(disable:4103) /* disable warning message 4103 that complains about pragma pack in a header file */
#pragma warning(disable:4127) /* "conditional expression is constant" (needed for static_assert) */
#pragma warning(disable:4996) /* POSIX name is deprecated */
#elif defined __GNUC__
#elif defined __clang__
#pragma GCC diagnostic ignored "-Wlogical-op-parentheses"
#pragma GCC diagnostic ignored "-Wbitwise-op-parentheses"
#endif
/* Some compilers do not support the #pragma align, which should be fine. Some
@ -337,15 +307,12 @@ typedef struct tagAMX_HEADER {
int32_t nametable PACKED; /* name table */
} AMX_HEADER;
#define AMX_MAGIC_16 0xf1e2
#define AMX_MAGIC_32 0xf1e0
#define AMX_MAGIC_64 0xf1e1
#if PAWN_CELL_SIZE==16
#define AMX_MAGIC AMX_MAGIC_16
#define AMX_MAGIC 0xf1e2
#elif PAWN_CELL_SIZE==32
#define AMX_MAGIC AMX_MAGIC_32
#define AMX_MAGIC 0xf1e0
#elif PAWN_CELL_SIZE==64
#define AMX_MAGIC AMX_MAGIC_64
#define AMX_MAGIC 0xf1e1
#endif
enum {
@ -410,51 +377,19 @@ enum {
#define amx_ftoc(f) ( * ((cell*)&f) ) /* float to cell */
#define amx_ctof(c) ( * ((double*)&c) ) /* cell to float */
#else
// amx_ftoc() and amx_ctof() cannot be used
#error Unsupported cell size
#endif
/* when a pointer cannot be stored in a cell, cells that hold relocated
* addresses need to be expanded
*/
#if defined __64BIT__ && PAWN_CELL_SIZE<64
#define CELLMASK (((int64_t)1 << PAWN_CELL_SIZE) - 1)
#define amx_Address(amx,addr) \
(cell*)(((int64_t)((amx)->data ? (amx)->data : (amx)->code) & ~CELLMASK) | ((int64_t)(addr) & CELLMASK))
#elif defined __32BIT__ && PAWN_CELL_SIZE<32
#define CELLMASK ((1L << PAWN_CELL_SIZE) - 1)
#define amx_Address(amx,addr) \
(cell*)(((int32_t)((amx)->data ? (amx)->data : (amx)->code) & ~CELLMASK) | ((int32_t)(addr) & CELLMASK))
#else
#define amx_Address(amx,addr) \
(cell*)(((int32_t)((amx)->data ? (amx)->data : (amx)->base+(int)((AMX_HEADER *)(amx)->base)->dat)) + ((int32_t)(addr)))
#endif
#if defined __STDC_VERSION__ && __STDC_VERSION__ >= 199901L
/* C99: use variable-length arrays */
#define amx_StrParam_Type(amx,param,result,type) \
int result##_length_; \
amx_StrLen(amx_Address(amx,param),&result##_length_); \
char result##_vla_[(result##_length_+1)*sizeof(*(result))]; \
(result)=(type)result##_vla_; \
amx_GetString((char*)(result),amx_Address(amx,param), \
sizeof(*(result))>1,result##_length_+1)
#define amx_StrParam(amx,param,result) \
amx_StrParam_Type(amx,param,result,void*)
#else
/* macro using alloca() */
#define amx_StrParam_Type(amx,param,result,type) \
#define amx_StrParam(amx,param,result) \
do { \
int result##_length_; \
amx_StrLen(amx_Address(amx,param),&result##_length_); \
if (result##_length_>0 && \
((result)=(type)alloca((result##_length_+1)*sizeof(*(result))))!=NULL) \
amx_GetString((char*)(result),amx_Address(amx,param), \
sizeof(*(result))>1,result##_length_+1); \
cell *amx_cstr_; int amx_length_; \
amx_GetAddr((amx), (param), &amx_cstr_); \
amx_StrLen(amx_cstr_, &amx_length_); \
if (amx_length_ > 0 && \
((result) = (void*)alloca((amx_length_ + 1) * sizeof(*(result)))) != NULL) \
amx_GetString((char*)(result), amx_cstr_, sizeof(*(result))>1, amx_length_ + 1); \
else (result) = NULL; \
} while (0)
#define amx_StrParam(amx,param,result) \
amx_StrParam_Type(amx,param,result,void*)
#endif
uint16_t * AMXAPI amx_Align16(uint16_t *v);
uint32_t * AMXAPI amx_Align32(uint32_t *v);
@ -504,24 +439,11 @@ int AMXAPI amx_UTF8Len(const cell *cstr, int *length);
int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value);
#if PAWN_CELL_SIZE==16
void amx_Swap16(uint16_t *v);
#endif
#if PAWN_CELL_SIZE==32
void amx_Swap32(uint32_t *v);
#endif
#if PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined INT64_MAX || defined HAVE_I64)
void amx_Swap64(uint64_t *v);
#endif
#if PAWN_CELL_SIZE==16
#define amx_AlignCell(v) amx_Align16((uint16_t*)(v))
#define amx_SwapCell(v) amx_Swap16((uint16_t*)(v))
#define amx_AlignCell(v) amx_Align16(v)
#elif PAWN_CELL_SIZE==32
#define amx_AlignCell(v) amx_Align32((uint32_t*)(v))
#define amx_SwapCell(v) amx_Swap32((uint32_t*)(v))
#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined INT64_MAX || defined HAVE_I64)
#define amx_AlignCell(v) amx_Align64((uint64_t*)(v))
#define amx_SwapCell(v) amx_Swap64((uint64_t*)(v))
#define amx_AlignCell(v) amx_Align32(v)
#elif PAWN_CELL_SIZE==64 && (defined _I64_MAX || defined HAVE_I64)
#define amx_AlignCell(v) amx_Align64(v)
#else
#error Unsupported cell size
#endif
@ -530,7 +452,7 @@ int AMXAPI amx_UTF8Put(char *string, char **endptr, int maxchars, cell value);
amx_Register((amx), amx_NativeInfo((name),(func)), 1);
#if !defined AMX_NO_ALIGN
#if defined __LINUX__ || defined __FreeBSD__ || defined __APPLE__
#if defined LINUX || defined __FreeBSD__
#pragma pack() /* reset default packing */
#elif defined MACOS && defined __MWERKS__
#pragma options align=reset

View File

@ -10,15 +10,15 @@
* All strings MUST have an explicit \0. See the Windows SDK documentation
* for details on version information and the VERSIONINFO structure.
*/
#define VERSION 4
#define REVISION 0
#define VERSION 1
#define REVISION 1
#define BUILD 0
#define VERSIONSTR "4.0.0\0"
#define VERSIONSTR "1.1.0\0"
#define VERSIONNAME "amxFile.dll\0"
#define VERSIONDESCRIPTION "Pawn AMX: File I/O support\0"
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
#define VERSIONPRODUCTNAME "amxFile\0"
#define VERSIONCOPYRIGHT "Copyright \251 2004-2016 ITB CompuPhase\0"
#define VERSIONCOPYRIGHT "Copyright \251 2004-2006 ITB CompuPhase\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION, REVISION, BUILD, 0

View File

@ -10,15 +10,15 @@
* All strings MUST have an explicit \0. See the Windows SDK documentation
* for details on version information and the VERSIONINFO structure.
*/
#define VERSION 4
#define VERSION 1
#define REVISION 0
#define BUILD 0
#define VERSIONSTR "4.0.0\0"
#define VERSIONSTR "1.0.0\0"
#define VERSIONNAME "amxFloat.dll\0"
#define VERSIONDESCRIPTION "Pawn AMX: Floating Point support\0"
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
#define VERSIONPRODUCTNAME "amxFloat\0"
#define VERSIONCOPYRIGHT "Copyright \251 2003-2013 ITB CompuPhase\0"
#define VERSIONCOPYRIGHT "Copyright \251 2003-2006 ITB CompuPhase\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION, REVISION, BUILD, 0

View File

@ -1,20 +1,24 @@
/* Script Arguments support module for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2005-2016
* Copyright (c) ITB CompuPhase, 2005-2006
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* http://www.apache.org/licenses/LICENSE-2.0
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxargs.c 5588 2016-10-25 11:13:28Z $
* Version: $Id: amxargs.c 3649 2006-10-12 13:13:57Z thiadmer $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
@ -32,16 +36,13 @@
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "osdefs.h"
#if defined __WIN32__ || defined __MSDOS__
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
#include <malloc.h>
#endif
#if defined __WIN32__ || defined _Windows
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
#include <windows.h>
#endif
#if defined __GNUC__ || defined __clang__
#include <unistd.h>
#endif
#include "osdefs.h"
#include "amx.h"
#if defined _UNICODE
@ -91,8 +92,8 @@ static const TCHAR *rawcmdline(void)
{
#if defined __WIN32__ || defined _WIN32 || defined WIN32
#elif defined _Windows || defined __MSDOS__
static char cmdbuffer[128]; /* DOS & Windows 3.1 are never in Unicode mode */
#elif defined __LINUX__
static char cmdbuffer[128];
#elif defined LINUX
static char cmdbuffer[1024]; /* some arbitrary maximum */
#endif
const TCHAR *ptr;
@ -115,7 +116,7 @@ static const TCHAR *rawcmdline(void)
if ((cmd == strchr(cmdbuffer, '\r')) != NULL)
*cmd = '\0'; /* also erase \r after the last option (if any) */
cmdline = cmdbuffer;
#elif defined __LINUX__
#elif defined LINUX
/* Options in /proc/<pid>/cmdline are delimited with '\0' characters
* rather than spaces.
*/
@ -132,6 +133,7 @@ static const TCHAR *rawcmdline(void)
fread(cmdbuffer, 1, fsize, fp);
fclose(fp);
cmdbuffer[fsize] = '\0'; /* terminate with double-zero */
// ??? convert to Unicode
/* convert '\0' characters to spaces, for uniform parsing */
for (ptr = cmdbuffer; *ptr != ' '; ptr = strchr(ptr, '\0') + 1)
*ptr = ' ';
@ -139,10 +141,7 @@ static const TCHAR *rawcmdline(void)
skip++;
} /* if */
#else
/* no mechanism for determining the commandline, so it
* must be supplied with amx_ArgsSetCmdLine() instead.
*/
ptr = "";
#error Platform not supported
#endif
/* skip leading white space */
@ -210,7 +209,7 @@ static const TCHAR *matcharg(const TCHAR *key, int skip, int *length)
int index, optlen, keylen;
const TCHAR *option, *vptr;
keylen = (key != NULL) ? (int)_tcslen(key) : 0;
keylen = (key != NULL) ? _tcslen(key) : 0;
index = 0;
while ((option = tokenize(cmdline, index, length)) != NULL) {
/* check for a colon or an equal sign (':' or '=') */
@ -229,7 +228,7 @@ static const TCHAR *matcharg(const TCHAR *key, int skip, int *length)
optlen++; /* if ':' or '=' was found, skip it too */
option += optlen; /* point behind option */
*length -= optlen; /* length of the value, not of the option */
assert(*length >= 0);
assert(length >= 0);
if (skip-- == 0)
break;
} /* if */
@ -253,7 +252,11 @@ static cell AMX_NATIVE_CALL n_argindex(AMX *amx, const cell *params)
max = (int)params[3];
if (max <= 0)
return 0;
cptr = amx_Address(amx, params[2]);
amx_GetAddr(amx, params[2], &cptr);
if (cptr == NULL) {
amx_RaiseError(amx, AMX_ERR_NATIVE);
return 0;
} /* if */
if ((option = tokenize(cmdline, params[1], &length)) == NULL) {
/* option not found, return an empty string */
@ -291,7 +294,11 @@ static cell AMX_NATIVE_CALL n_argstr(AMX *amx, const cell *params)
if (max <= 0)
return 0;
amx_StrParam(amx, params[2], key);
cptr = amx_Address(amx, params[3]);
amx_GetAddr(amx, params[3], &cptr);
if (cptr == NULL) {
amx_RaiseError(amx, AMX_ERR_NATIVE);
return 0;
} /* if */
option = matcharg(key, (int)params[1], &length);
if (option == NULL)
@ -330,7 +337,11 @@ static cell AMX_NATIVE_CALL n_argvalue(AMX *amx, const cell *params)
cell *cptr;
amx_StrParam(amx, params[2], key);
cptr = amx_Address(amx, params[3]);
amx_GetAddr(amx, params[3], &cptr);
if (cptr == NULL) {
amx_RaiseError(amx, AMX_ERR_NATIVE);
return 0;
} /* if */
option = matcharg(key, (int)params[1], &length);
if (option == NULL)
@ -367,12 +378,12 @@ const AMX_NATIVE_INFO args_Natives[] = {
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_ArgsInit(AMX *amx)
int AMXEXPORT amx_ArgsInit(AMX *amx)
{
return amx_Register(amx, args_Natives, -1);
}
int AMXEXPORT AMXAPI amx_ArgsCleanup(AMX *amx)
int AMXEXPORT amx_ArgsCleanup(AMX *amx)
{
(void)amx;
return AMX_ERR_NONE;
@ -384,7 +395,7 @@ int AMXEXPORT AMXAPI amx_ArgsCleanup(AMX *amx)
* that is passed in to this function is NOT copied, so it may not be freed
* after the call.
*/
int AMXEXPORT AMXAPI amx_ArgsSetCmdLine(const TCHAR *cmd)
int AMXEXPORT amx_ArgsSetCmdLine(const TCHAR *cmd)
{
cmdline = cmd;
return AMX_ERR_NONE;

View File

@ -1,6 +0,0 @@
NAME amxArgs
DESCRIPTION 'Pawn AMX: Script Arguments support'
EXPORTS
amx_ArgsInit
amx_ArgsCleanup

View File

@ -10,15 +10,15 @@
* All strings MUST have an explicit \0. See the Windows SDK documentation
* for details on version information and the VERSIONINFO structure.
*/
#define VERSION 4
#define VERSION 1
#define REVISION 0
#define BUILD 0
#define VERSIONSTR "4.0.0\0"
#define VERSIONSTR "1.0.0\0"
#define VERSIONNAME "amxArgs.dll\0"
#define VERSIONDESCRIPTION "Pawn AMX: Script Arguments support\0"
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
#define VERSIONPRODUCTNAME "amxArgs\0"
#define VERSIONCOPYRIGHT "Copyright \251 2005-2016 ITB CompuPhase\0"
#define VERSIONCOPYRIGHT "Copyright \251 2005-2006 ITB CompuPhase\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION, REVISION, BUILD, 0

View File

@ -4,21 +4,25 @@
* cannot always be implemented with portable C functions. In other words,
* these routines must be ported to other environments.
*
* Copyright (c) ITB CompuPhase, 1997-2016
* Copyright (c) ITB CompuPhase, 1997-2006
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* http://www.apache.org/licenses/LICENSE-2.0
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxcons.c 5587 2016-10-25 09:59:46Z $
* Version: $Id: amxcons.c 3649 2006-10-12 13:13:57Z thiadmer $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
@ -36,26 +40,13 @@
#include <string.h>
#include <assert.h>
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
#define HAVE_CONIO
#include <conio.h>
#include <malloc.h>
#endif
#if defined USE_CURSES || defined HAVE_CURSES_H
#if defined USE_CURSES
#include <curses.h>
#if !defined CURSES
#define CURSES 1
#endif
#endif
#include "osdefs.h"
#if defined __ECOS__
/* eCos puts include files in cyg/package_name */
#include <cyg/hal/hal_if.h>
#include <cyg/infra/diag.h>
#include <cyg/hal/hal_diag.h>
#include <cyg/pawn/amx.h>
#else
#include "amx.h"
#endif
#include "amx.h"
#if defined __WIN32__ || defined _WIN32 || defined WIN32
#include <windows.h>
#endif
@ -65,21 +56,18 @@
#elif !defined __T
typedef char TCHAR;
# define __T(string) string
# define _fgetts fgets
# define _puttchar putchar
# define _stprintf sprintf
# define _tcschr strchr
# define _tcscpy strcpy
# define _tcsdup strdup
# define _tcslen strlen
# define _tprintf printf
# define _stprintf sprintf
#endif
#include "amxcons.h"
#if defined AMX_TERMINAL
#if defined __MSDOS__
#define EOL_CHAR '\r'
#endif
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
#if defined __WIN32__ || defined _WIN32 || defined WIN32
#define EOL_CHAR '\r'
#endif
#if !defined EOL_CHAR
@ -99,118 +87,17 @@
int amx_termctl(int,int);
void amx_clrscr(void);
void amx_clreol(void);
int amx_gotoxy(int x,int y);
void amx_gotoxy(int x,int y);
void amx_wherexy(int *x,int *y);
unsigned int amx_setattr(int foregr,int backgr,int highlight);
void amx_console(int columns, int lines, int flags);
void amx_viewsize(int *width,int *height);
int amx_kbhit(void);
#elif defined CURSES && CURSES != 0
/* Use the "curses" library to implement the console */
static WINDOW *curseswin;
#define amx_putstr(s) printw("%s",(s))
#define amx_putchar(c) addch(c)
#define amx_fflush() refresh()
#define amx_getch() getch()
#define amx_gets(s,n) getnstr((s),(n))
#define amx_clrscr() clear()
#define amx_clreol() clrtoeol()
#define amx_gotoxy(x,y) move((y)-1,(x)-1)
#define amx_console(c,l,f) ((void)(c),(void)(l),(void)(f))
unsigned int amx_setattr(int foregr,int backgr,int highlight)
{
if (highlight>0)
attron(A_STANDOUT);
else
attroff(A_STANDOUT);
//??? in future, also handle colours
}
void CreateConsole(void);
int amx_kbhit(void)
{
int result;
CreateConsole();
nodelay(curseswin,TRUE); /* enter non-blocking state */
result=getch(); /* read key (if any) */
nodelay(curseswin,FALSE); /* leave non-blocking state */
if (result!=ERR)
ungetch(result); /* a key is waiting, push it back */
return (result==ERR) ? 0 : 1;
}
int amx_termctl(int code,int value)
{
switch (code) {
case 0: /* query terminal support */
return 1;
/* case 1: */ /* switch auto-wrap on/off (not supported in curses!) */
/* case 2: */ /* create/switch to another console */
case 3: /* set emphasized font */
if (value)
attron(A_BOLD);
else
attroff(A_BOLD);
return 1;
/* case 4: */ /* query whether a terminal is "open" */
default:
return 0;
} /* switch */
}
void amx_wherexy(int *x,int *y)
{
int row,col;
getyx(curseswin,row,col);
if (x!=NULL)
*x=col+1;
if (y!=NULL)
*y=row+1;
}
void amx_viewsize(int *width,int *height)
{
int row,col;
getmaxyx(curseswin,row,col);
if (width!=NULL)
*width=col;
if (height!=NULL)
*height=row;
}
#elif defined VT100 || defined __LINUX__ || defined ANSITERM || defined __ECOS__
#elif defined VT100 || defined LINUX || defined ANSITERM
/* ANSI/VT100 terminal, or shell emulating "xterm" */
#if defined __ECOS__
#define AMXCONSOLE_NOIDLE
#endif
#if CYGPKG_PAWN_AMXCONSOLE_DIAG==1
/* eCos has basically two ways to make simple exchanges with a terminal:
* - with the diag_*() functions (no input provided!)
* - with f*() functions (fprintf(),fputs(), etc).
*/
#define amx_fflush()
static int amx_putstr(TCHAR *s)
{
diag_write_string(s);
return 1;
}
static int amx_putchar(TCHAR c)
{
diag_write_char(c);
return c;
}
static char amx_getch(void)
{
char c=-1;
HAL_DIAG_READ_CHAR(c);
return c;
}
#else
#define amx_putstr(s) fputs((s),stdout)
#define amx_putchar(c) putchar(c)
#define amx_fflush() fflush(stdout)
#define amx_getch() getch()
#define amx_gets(s,n) fgets(s,n,stdin)
#define amx_kbhit() kbhit()
#endif
#define amx_putstr(s) printf("%s",(s))
#define amx_putchar(c) putchar(c)
#define amx_fflush() fflush(stdout)
#define amx_getch() getch()
#define amx_gets(s,n) fgets(s,n,stdin)
int amx_termctl(int code,int value)
{
@ -257,13 +144,12 @@
amx_putstr("\033[K");
amx_fflush(); /* pump through the terminal codes */
}
int amx_gotoxy(int x,int y)
void amx_gotoxy(int x,int y)
{
char str[30];
_stprintf(str,"\033[%d;%dH",y,x);
amx_putstr(str);
amx_fflush(); /* pump through the terminal codes */
return 1;
}
void amx_wherexy(int *x,int *y)
{
@ -280,13 +166,11 @@
for (i=0; i<8 && (val=amx_getch())!=';'; i++)
str[i]=(char)val;
str[i]='\0';
if (y!=NULL)
*y=atoi(str);
*y=atoi(str);
for (i=0; i<8 && (val=amx_getch())!='R'; i++)
str[i]=(char)val;
str[i]='\0';
if (x!=NULL)
*x=atoi(str);
*x=atoi(str);
#if defined ANSITERM
val=amx_getch();
assert(val=='\r'); /* ANSI driver adds CR to the end of the command */
@ -330,20 +214,13 @@
amx_putstr(str);
amx_fflush();
}
void amx_viewsize(int *width,int *height)
{
/* a trick to get the size of the terminal is to position the cursor far
* away and then read it back
*/
amx_gotoxy(999,999);
amx_wherexy(width,height);
}
#elif defined __WIN32__ || defined _WIN32 || defined WIN32
/* Win32 console */
#define amx_putstr(s) _tprintf("%s",(s))
#define amx_putchar(c) _puttchar(c)
#define amx_fflush() fflush(stdout)
#define amx_gets(s,n) _fgetts(s,n,stdin)
#define amx_putstr(s) printf("%s",(s))
#define amx_putchar(c) putchar(c)
#define amx_fflush() fflush(stdout)
#define amx_getch() getch()
#define amx_gets(s,n) fgets(s,n,stdin)
int amx_termctl(int code,int value)
{
@ -354,13 +231,10 @@
case 1: { /* switch auto-wrap on/off */
/* only works in Windows 2000/XP */
HANDLE hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
DWORD mode;
GetConsoleMode(hConsole,&mode);
DWORD Flags=ENABLE_PROCESSED_OUTPUT;
if (value)
mode |= ENABLE_WRAP_AT_EOL_OUTPUT;
else
mode &= ~ENABLE_WRAP_AT_EOL_OUTPUT;
SetConsoleMode(hConsole,mode);
Flags |= ENABLE_WRAP_AT_EOL_OUTPUT;
SetConsoleMode(hConsole,Flags);
return 1;
} /* case */
@ -399,7 +273,7 @@
FillConsoleOutputCharacter(hConsole,' ',dwConSize,csbi.dwCursorPosition,&cCharsWritten);
FillConsoleOutputAttribute(hConsole,csbi.wAttributes,dwConSize,csbi.dwCursorPosition,&cCharsWritten);
}
int amx_gotoxy(int x,int y)
void amx_gotoxy(int x,int y)
{
COORD point;
CONSOLE_SCREEN_BUFFER_INFO csbi;
@ -407,12 +281,11 @@
GetConsoleScreenBufferInfo(hConsole, &csbi);
if (x<=0 || x>csbi.dwSize.X || y<=0 || y>csbi.dwSize.Y)
return 0;
return;
amx_fflush(); /* make sure all output is written */
point.X=(short)(x-1);
point.Y=(short)(y-1);
SetConsoleCursorPosition(hConsole,point);
return 1;
}
void amx_wherexy(int *x,int *y)
{
@ -450,58 +323,30 @@
{
SMALL_RECT rect;
COORD dwSize;
HANDLE hConsole;
(void)flags;
dwSize.X=(short)columns;
dwSize.Y=(short)lines;
hConsole=GetStdHandle(STD_OUTPUT_HANDLE);
SetConsoleScreenBufferSize(hConsole,dwSize);
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE),dwSize);
rect.Left=0;
rect.Top=0;
rect.Right=(short)(columns-1);
rect.Bottom=(short)(lines-1);
SetConsoleWindowInfo(hConsole,TRUE,&rect);
}
void amx_viewsize(int *width,int *height)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE),&csbi);
if (width!=NULL)
*width=(int)csbi.dwSize.X;
if (height!=NULL)
*height=(int)(csbi.srWindow.Bottom-csbi.srWindow.Top+1);
}
int amx_getch(void)
{
TCHAR ch;
DWORD count,mode;
HANDLE hConsole=GetStdHandle(STD_INPUT_HANDLE);
GetConsoleMode(hConsole,&mode);
SetConsoleMode(hConsole,mode & ~(ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT));
while (ReadFile(hConsole,&ch,1,&count,NULL) && count==0)
/* nothing */;
SetConsoleMode(hConsole,mode);
if (count>0)
return ch;
return EOF;
}
int amx_kbhit(void)
{
DWORD count=0;
HANDLE hConsole;
hConsole=GetStdHandle(STD_INPUT_HANDLE);
if (GetFileType(hConsole)==FILE_TYPE_PIPE) {
PeekNamedPipe(hConsole,NULL,0,NULL,&count,NULL);
} else {
INPUT_RECORD rec;
while (PeekConsoleInput(hConsole,&rec,1,&count)) {
if (count==0 || (rec.EventType==KEY_EVENT && rec.Event.KeyEvent.bKeyDown))
break;
ReadConsoleInput(hConsole,&rec,1,&count);
}
}
return (count>0);
SetConsoleWindowInfo(GetStdHandle(STD_OUTPUT_HANDLE),TRUE,&rect);
}
#elif defined USE_CURSES
/* Use the "curses" library to implement the console */
#define amx_putstr(s) printw("%s",(s))
#define amx_putchar(c) addch(c)
#define amx_fflush() (0)
#define amx_getch() getch()
#define amx_gets(s,n) getnstr(s,n)
#define amx_clrscr() clear()
#define amx_clreol() clrtoeol()
#define amx_gotoxy(x,y) (void)(0)
#define amx_wherexy(x,y) (*(x)=*(y)=0)
#define amx_setattr(c,b,h) (0)
#define amx_termctl(c,v) (0)
#define amx_console(c,l,f) (void)(0)
#else
/* assume a streaming terminal; limited features (no colour, no cursor
* control)
@ -509,22 +354,15 @@
#define amx_putstr(s) printf("%s",(s))
#define amx_putchar(c) putchar(c)
#define amx_fflush() fflush(stdout)
#define amx_getch() getch()
#define amx_gets(s,n) fgets(s,n,stdin)
#define amx_clrscr() (void)(0)
#define amx_clreol() (void)(0)
#define amx_gotoxy(x,y) ((void)(x),(void)(y),(0))
#define amx_gotoxy(x,y) ((void)(x),(void)(y))
#define amx_wherexy(x,y) (*(x)=*(y)=0)
#define amx_setattr(c,b,h) ((void)(c),(void)(b),(void)(h),(0))
#define amx_termctl(c,v) ((void)(c),(void)(v),(0))
#define amx_console(c,l,f) ((void)(c),(void)(l),(void)(f))
#define amx_viewsize (*(x)=80,*(y)=25)
#if defined HAVE_CONIO
#define amx_getch() getch()
#define amx_kbhit() kbhit()
#else
#define amx_getch() getchar()
#define amx_kbhit() (0)
#endif
#endif
#if !defined AMX_TERMINAL && (defined __WIN32__ || defined _WIN32 || defined WIN32)
@ -535,22 +373,20 @@
createdconsole=1;
} /* if */
}
#elif defined CURSES && CURSES != 0
#elif defined USE_CURSES
// The Mac OS X build variant uses curses.
void CreateConsole(void)
{ static int createdconsole=0;
if (!createdconsole) {
curseswin=initscr();
if (has_colors())
start_color();
initscr();
cbreak();
noecho();
nonl();
scrollok(curseswin,TRUE);
intrflush(curseswin,FALSE);
keypad(curseswin,TRUE);
createdconsole=1;
} /* if */
intrflush(stdscr, FALSE);
keypad(stdscr, TRUE);
createdconsole=1;
} /* if */
}
#else
#define CreateConsole()
@ -610,19 +446,12 @@ static TCHAR *amx_strval(TCHAR buffer[], long value, int format, int width)
if (value < 0) {
buffer[0] = __T('-');
start = stop = 1;
do {
temp = (TCHAR)(value % 10);
if (temp > 0)
temp = (TCHAR)(temp - 10);
buffer[stop++] = (TCHAR)(__T('0') - temp);
value /= 10;
} while (value != 0);
} else {
do {
buffer[stop++] = (TCHAR)((value % 10) + __T('0'));
value /= 10;
} while (value != 0);
}
value = -value;
} /* if */
do {
buffer[stop++] = (TCHAR)((value % 10) + __T('0'));
value /= 10;
} while (value > 0);
} else {
/* hexadecimal */
unsigned long v = (unsigned long)value; /* copy to unsigned value for shifting */
@ -690,7 +519,7 @@ static TCHAR *formatfixed(TCHAR *string,cell value,TCHAR align,int width,TCHAR d
string[0]=__T('\0');
/* add sign */
i=(int)_tcslen(string);
i=_tcslen(string);
string[i]=vsign;
string[i+1]=__T('\0');
@ -699,12 +528,12 @@ static TCHAR *formatfixed(TCHAR *string,cell value,TCHAR align,int width,TCHAR d
/* add fractional part */
if (digits>0) {
i=(int)_tcslen(string);
i=_tcslen(string);
string[i]=decpoint;
amx_strval(string+i+1,(long)value,SV_DECIMAL,-digits);
} /* if */
len=(int)_tcslen(string);
len=_tcslen(string);
if (len<width) {
/* pad to the requested width */
for (i=len; i<width; i++)
@ -741,8 +570,12 @@ static int dochar(AMX *amx,TCHAR ch,cell param,TCHAR sign,TCHAR decpoint,int wid
assert(f_putchar!=NULL);
switch (ch) {
case __T('%'):
f_putchar(user,ch);
return 0;
case __T('c'):
cptr=amx_Address(amx,param);
amx_GetAddr(amx,param,&cptr);
width--; /* single character itself has a with of 1 */
if (sign!=__T('-'))
while (width-->0)
@ -755,7 +588,7 @@ static int dochar(AMX *amx,TCHAR ch,cell param,TCHAR sign,TCHAR decpoint,int wid
case __T('d'): {
cell value;
int length=1;
cptr=amx_Address(amx,param);
amx_GetAddr(amx,param,&cptr);
value=*cptr;
if (value<0 || sign==__T('+'))
length++;
@ -792,17 +625,9 @@ static int dochar(AMX *amx,TCHAR ch,cell param,TCHAR sign,TCHAR decpoint,int wid
if (width>0)
_stprintf(formatstring+_tcslen(formatstring),__T("%d"),width);
_stprintf(formatstring+_tcslen(formatstring),__T(".%df"),digits);
cptr=amx_Address(amx,param);
#if PAWN_CELL_SIZE == 64
_stprintf(buffer,formatstring,*(double*)cptr);
#else
_stprintf(buffer,formatstring,*(float*)cptr);
#endif
if (decpoint==__T(',')) {
TCHAR *ptr=_tcschr(buffer,__T('.'));
if (ptr!=NULL)
*ptr=__T(',');
} /* if */
/* ??? decimal comma? */
amx_GetAddr(amx,param,&cptr);
_stprintf(buffer,formatstring,*(float*)cptr);
f_putstr(user,buffer);
return 1;
#endif
@ -813,7 +638,7 @@ static int dochar(AMX *amx,TCHAR ch,cell param,TCHAR sign,TCHAR decpoint,int wid
#if !defined FLOATPOINT
case __T('r'): /* if fixed point is enabled, and floating point is not, %r == %q */
#endif
cptr=amx_Address(amx,param);
amx_GetAddr(amx,param,&cptr);
/* format the number */
if (digits==INT_MAX)
digits=3;
@ -840,7 +665,7 @@ static int dochar(AMX *amx,TCHAR ch,cell param,TCHAR sign,TCHAR decpoint,int wid
info.f_putstr=f_putstr;
info.f_putchar=f_putchar;
info.user=user;
cptr=amx_Address(amx,param);
amx_GetAddr(amx,param,&cptr);
amx_printstring(amx,cptr,&info);
return 1;
} /* case */
@ -848,7 +673,7 @@ static int dochar(AMX *amx,TCHAR ch,cell param,TCHAR sign,TCHAR decpoint,int wid
case __T('x'): {
ucell value;
int length=1;
cptr=amx_Address(amx,param);
amx_GetAddr(amx,param,&cptr);
value=*(ucell*)cptr;
while (value>=0x10) {
length++;
@ -873,7 +698,7 @@ static int dochar(AMX *amx,TCHAR ch,cell param,TCHAR sign,TCHAR decpoint,int wid
enum {
FMT_NONE, /* not in format state; accept '%' */
FMT_START, /* found '%', accept '+', '-' (START), '0' (filler; START), digit (WIDTH), '.' (DECIM), or '%' or format letter (done) */
FMT_START, /* found '%', accept '+', '-' (START), '0' (filler; START), digit (WIDTH), '.' (DECIM) or format letter (done) */
FMT_WIDTH, /* found digit after '%' or sign, accept digit (WIDTH), '.' (DECIM) or format letter (done) */
FMT_DECIM, /* found digit after '.', accept accept digit (DECIM) or format letter (done) */
};
@ -906,11 +731,8 @@ static int formatstate(TCHAR c,int *state,TCHAR *sign,TCHAR *decpoint,int *width
*decpoint=c;
*digits=0;
*state=FMT_DECIM;
} else if (c==__T('%')) {
*state=FMT_NONE;
return -1; /* print literal '%' */
} else {
return 1; /* print formatted character */
return 1; /* print formatted character */
} /* if */
break;
case FMT_WIDTH:
@ -921,14 +743,14 @@ static int formatstate(TCHAR c,int *state,TCHAR *sign,TCHAR *decpoint,int *width
*digits=0;
*state=FMT_DECIM;
} else {
return 1; /* print formatted character */
return 1; /* print formatted character */
} /* if */
break;
case FMT_DECIM:
if (c>=__T('0') && c<=__T('9')) {
*digits=*digits*10+(int)(c-__T('0'));
} else {
return 1; /* print formatted character */
return 1; /* print formatted character */
} /* if */
break;
} /* switch */
@ -976,10 +798,11 @@ int amx_printstring(AMX *amx,cell *cstr,AMX_FMTINFO *info)
if ((ucell)*cstr>UNPACKEDMAX) {
int j=sizeof(cell)-sizeof(char);
char c;
/* the string is packed */
i=0;
for ( ; ; ) {
char c=(char)((ucell)cstr[i] >> 8*j);
c=(char)((ucell)cstr[i] >> 8*j);
if (c==0)
break;
if (skip>0) {
@ -1023,29 +846,28 @@ int amx_printstring(AMX *amx,cell *cstr,AMX_FMTINFO *info)
/* check whether this is a packed string */
if ((ucell)*cstr>UNPACKEDMAX) {
int j=sizeof(cell)-sizeof(char);
char c;
/* the string is packed */
i=0;
for ( ; ; ) {
char c=(char)((ucell)cstr[i] >> 8*j);
c=(char)((ucell)cstr[i] >> 8*j);
if (c==0)
break;
switch (formatstate(c,&fmtstate,&sign,&decpoint,&width,&digits,&filler)) {
case -1:
f_putchar(user,c);
break;
case 0:
break;
case 1:
assert(info!=NULL && info->params!=NULL);
paramidx+=dochar(amx,c,info->params[paramidx],sign,decpoint,width,digits,filler,
f_putstr,f_putchar,user);
fmtstate=FMT_NONE;
break;
case 0:
assert(info!=NULL && info->params!=NULL);
if (paramidx>=info->numparams) /* insufficient parameters passed */
amx_RaiseError(amx, AMX_ERR_NATIVE);
else
paramidx+=dochar(amx,c,info->params[paramidx],sign,decpoint,width,digits,filler,
f_putstr,f_putchar,user);
fmtstate=FMT_NONE;
break;
default:
assert(0);
} /* switch */
if (j==0)
i++;
@ -1058,19 +880,17 @@ int amx_printstring(AMX *amx,cell *cstr,AMX_FMTINFO *info)
case -1:
f_putchar(user,(TCHAR)cstr[i]);
break;
case 0:
break;
case 1:
assert(info!=NULL && info->params!=NULL);
paramidx+=dochar(amx,(TCHAR)cstr[i],info->params[paramidx],sign,decpoint,width,digits,filler,
f_putstr,f_putchar,user);
fmtstate=FMT_NONE;
break;
case 0:
assert(info!=NULL && info->params!=NULL);
if (paramidx>=info->numparams) /* insufficient parameters passed */
amx_RaiseError(amx, AMX_ERR_NATIVE);
else
paramidx+=dochar(amx,(TCHAR)cstr[i],info->params[paramidx],sign,decpoint,width,digits,filler,
f_putstr,f_putchar,user);
fmtstate=FMT_NONE;
break;
default:
assert(0);
} /* switch */
} /* for */
} /* if */
@ -1094,7 +914,7 @@ static cell AMX_NATIVE_CALL n_print(AMX *amx,const cell *params)
info.length= ((size_t)params[0]>=3*sizeof(cell)) ? (int)(params[3]-info.skip) : INT_MAX;
CreateConsole();
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
amx_printstring(amx,cstr,&info);
amx_fflush();
return 0;
@ -1111,7 +931,7 @@ static cell AMX_NATIVE_CALL n_print(AMX *amx,const cell *params)
/* set the new colours */
oldcolours=amx_setattr((int)params[2],(int)params[3],(int)params[4]);
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
amx_printstring(amx,cstr,NULL);
/* reset the colours */
@ -1133,7 +953,7 @@ static cell AMX_NATIVE_CALL n_printf(AMX *amx,const cell *params)
info.length=INT_MAX;
CreateConsole();
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
amx_printstring(amx,cstr,&info);
amx_fflush();
return 0;
@ -1162,20 +982,18 @@ static cell AMX_NATIVE_CALL n_getchar(AMX *amx,const cell *params)
static cell AMX_NATIVE_CALL n_getstring(AMX *amx,const cell *params)
{
int c,chars,max;
TCHAR *str;
cell *cptr;
(void)amx;
CreateConsole();
chars=0;
max=(int)params[2];
if (max>0) {
#if __STDC_VERSION__ >= 199901L
TCHAR str[max]; /* use C99 feature if available */
#else
TCHAR *str=(TCHAR *)alloca(max*sizeof(TCHAR));
if (str==NULL)
return chars;
#endif
if (max<=0)
return 0;
chars=0;
str=(TCHAR *)alloca(max*sizeof(TCHAR));
if (str!=NULL) {
c=amx_getch();
while (c!=EOF && c!=EOL_CHAR && chars<max-1) {
@ -1195,7 +1013,7 @@ static cell AMX_NATIVE_CALL n_getstring(AMX *amx,const cell *params)
assert(chars<max);
str[chars]='\0';
cptr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cptr);
amx_SetString(cptr,(char*)str,(int)params[3],sizeof(TCHAR)>1,max);
} /* if */
@ -1234,14 +1052,13 @@ static int inlist(AMX *amx,int c,const cell *params,int num)
{
int i, key;
(void)amx;
for (i=0; i<num; i++) {
if (i==0) {
/* first key is passed by value, others are passed by reference */
key = (int)params[i];
} else {
cell *cptr;
cptr=amx_Address(amx,params[i]);
amx_GetAddr(amx,params[i],&cptr);
key=(int)*cptr;
} /* if */
if (c==key || c==-key)
@ -1279,8 +1096,8 @@ static cell AMX_NATIVE_CALL n_getvalue(AMX *amx,const cell *params)
} /* if */
/* check end of input */
#if EOL_CHAR!='\r'
if (c==EOL_CHAR && inlist(amx,'\r',params+2,(int)params[0]/sizeof(cell)-1)!=0)
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined MACOS
if (c=='\n' && inlist(amx,'\r',params+2,(int)params[0]/sizeof(cell)-1)!=0)
c='\r';
#endif
if ((chars>1 || (chars>0 && sign>0))
@ -1290,10 +1107,6 @@ static cell AMX_NATIVE_CALL n_getvalue(AMX *amx,const cell *params)
acceptchar(c,&chars);
break;
} /* if */
#if EOL_CHAR!='\r'
if (c=='\r')
c=EOL_CHAR;
#endif
/* get value */
d=base; /* by default, do not accept the character */
@ -1340,7 +1153,8 @@ static cell AMX_NATIVE_CALL n_gotoxy(AMX *amx,const cell *params)
{
(void)amx;
CreateConsole();
return amx_gotoxy((int)params[1],(int)params[2]);
amx_gotoxy((int)params[1],(int)params[2]);
return 0;
}
static cell AMX_NATIVE_CALL n_wherexy(AMX *amx,const cell *params)
@ -1348,13 +1162,12 @@ static cell AMX_NATIVE_CALL n_wherexy(AMX *amx,const cell *params)
cell *px,*py;
int x,y;
(void)amx;
CreateConsole();
amx_wherexy(&x,&y);
px=amx_Address(amx,params[1]);
py=amx_Address(amx,params[2]);
*px=x;
*py=y;
amx_GetAddr(amx,params[1],&px);
amx_GetAddr(amx,params[2],&py);
if (px!=NULL) *px=x;
if (py!=NULL) *py=y;
return 0;
}
@ -1370,7 +1183,8 @@ static cell AMX_NATIVE_CALL n_consctrl(AMX *amx,const cell *params)
{
(void)amx;
CreateConsole();
return amx_termctl((int)params[1],(int)params[2]);
(void)amx_termctl((int)params[1],(int)params[2]);
return 0;
}
static cell AMX_NATIVE_CALL n_console(AMX *amx,const cell *params)
@ -1395,8 +1209,8 @@ static int AMXAPI amx_ConsoleIdle(AMX *amx, int AMXAPI Exec(AMX *, cell *, int))
if (PrevIdle != NULL)
PrevIdle(amx, Exec);
if (amx_kbhit()) {
key = amx_getch();
if (kbhit()) {
key = getch();
amx_Push(amx, key);
err = Exec(amx, NULL, idxKeyPressed);
while (err == AMX_ERR_SLEEP)
@ -1426,7 +1240,7 @@ const AMX_NATIVE_INFO console_Natives[] = {
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_ConsoleInit(AMX *amx)
int AMXEXPORT amx_ConsoleInit(AMX *amx)
{
#if !defined AMXCONSOLE_NOIDLE
/* see whether there is an @keypressed() function */
@ -1440,7 +1254,7 @@ int AMXEXPORT AMXAPI amx_ConsoleInit(AMX *amx)
return amx_Register(amx, console_Natives, -1);
}
int AMXEXPORT AMXAPI amx_ConsoleCleanup(AMX *amx)
int AMXEXPORT amx_ConsoleCleanup(AMX *amx)
{
(void)amx;
#if !defined AMXCONSOLE_NOIDLE

View File

@ -1,20 +1,24 @@
/* Core module for the Pawn AMX
*
* Copyright (c) ITB CompuPhase, 1997-2016
* Copyright (c) ITB CompuPhase, 1997-2006
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* http://www.apache.org/licenses/LICENSE-2.0
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxcore.c 5504 2016-05-15 13:42:30Z $
* Version: $Id: amxcore.c 3657 2006-10-24 20:09:50Z thiadmer $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
@ -30,14 +34,7 @@
#include <string.h>
#include <limits.h>
#include <assert.h>
#include "osdefs.h"
#if defined __ECOS__
/* eCos puts include files in cyg/package_name */
#include <cyg/pawn/amx.h>
#define stricmp(a,b) strcasecmp(a,b)
#else
#include "amx.h"
#endif
#include "amx.h"
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
#include <windows.h>
#endif
@ -199,10 +196,18 @@ static cell AMX_NATIVE_CALL funcidx(AMX *amx,const cell *params)
{
char name[64];
cell *cstr;
int index,err;
int index,err,len;
cstr=amx_Address(amx,params[1]);
amx_GetString(name,cstr,0,sizeof name);
amx_GetAddr(amx,params[1],&cstr);
/* verify string length */
amx_StrLen(cstr,&len);
if (len>=64) {
amx_RaiseError(amx,AMX_ERR_NATIVE);
return 0;
} /* if */
amx_GetString(name,cstr,0,UNLIMITED);
err=amx_FindPublic(amx,name,&index);
if (err!=AMX_ERR_NONE)
index=-1; /* this is not considered a fatal error */
@ -272,9 +277,9 @@ static cell AMX_NATIVE_CALL swapchars(AMX *amx,const cell *params)
static cell AMX_NATIVE_CALL core_tolower(AMX *amx,const cell *params)
{
(void)amx;
#if (defined __WIN32__ || defined _WIN32 || defined WIN32) && !defined _WIN64
#if defined __WIN32__ || defined _WIN32 || defined WIN32
return (cell)CharLower((LPTSTR)params[1]);
#elif defined _Windows && !defined _WIN64
#elif defined _Windows
return (cell)AnsiLower((LPSTR)params[1]);
#else
if ((unsigned)(params[1]-'A')<26u)
@ -286,9 +291,9 @@ static cell AMX_NATIVE_CALL core_tolower(AMX *amx,const cell *params)
static cell AMX_NATIVE_CALL core_toupper(AMX *amx,const cell *params)
{
(void)amx;
#if (defined __WIN32__ || defined _WIN32 || defined WIN32) && !defined _WIN64
#if defined __WIN32__ || defined _WIN32 || defined WIN32
return (cell)CharUpper((LPTSTR)params[1]);
#elif defined _Windows && !defined _WIN64
#elif defined _Windows
return (cell)AnsiUpper((LPSTR)params[1]);
#else
if ((unsigned)(params[1]-'a')<26u)
@ -329,31 +334,44 @@ static char *MakePackedString(cell *cptr)
amx_StrLen(cptr,&len);
dest=(char *)malloc(len+sizeof(cell));
amx_GetString(dest,cptr,0,len+sizeof(cell));
amx_GetString(dest,cptr,0,UNLIMITED);
return dest;
}
/* getproperty(id=0, const name[]="", value=cellmin, string[]="", size=sizeof string) */
static int verify_addr(AMX *amx,cell addr)
{
int err;
cell *cdest;
err=amx_GetAddr(amx,addr,&cdest);
if (err!=AMX_ERR_NONE)
amx_RaiseError(amx,err);
return err;
}
static cell AMX_NATIVE_CALL getproperty(AMX *amx,const cell *params)
{
cell *cstr;
char *name;
proplist *item;
(void)amx;
cstr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cstr);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
/* if list_finditem() found the value, store the name */
if (item!=NULL && item->value==params[3] && strlen(name)==0) {
cstr=amx_Address(amx,params[4]);
amx_SetString(cstr,item->name,1,0,params[5]);
int needed=(strlen(item->name)+sizeof(cell)-1)/sizeof(cell); /* # of cells needed */
if (verify_addr(amx,(cell)(params[4]+needed))!=AMX_ERR_NONE) {
free(name);
return 0;
} /* if */
amx_GetAddr(amx,params[4],&cstr);
amx_SetString(cstr,item->name,1,0,UNLIMITED);
} /* if */
free(name);
return (item!=NULL) ? item->value : 0;
}
/* setproperty(id=0, const name[]="", value=cellmin, const string[]="") */
static cell AMX_NATIVE_CALL setproperty(AMX *amx,const cell *params)
{
cell prev=0;
@ -361,7 +379,7 @@ static cell AMX_NATIVE_CALL setproperty(AMX *amx,const cell *params)
char *name;
proplist *item;
cstr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cstr);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
if (item==NULL)
@ -372,7 +390,7 @@ static cell AMX_NATIVE_CALL setproperty(AMX *amx,const cell *params)
prev=item->value;
if (strlen(name)==0) {
free(name);
cstr=amx_Address(amx,params[4]);
amx_GetAddr(amx,params[4],&cstr);
name=MakePackedString(cstr);
} /* if */
list_setitem(item,params[1],name,params[3]);
@ -381,7 +399,6 @@ static cell AMX_NATIVE_CALL setproperty(AMX *amx,const cell *params)
return prev;
}
/* deleteproperty(id=0, const name[]="", value=cellmin) */
static cell AMX_NATIVE_CALL delproperty(AMX *amx,const cell *params)
{
cell prev=0;
@ -389,8 +406,7 @@ static cell AMX_NATIVE_CALL delproperty(AMX *amx,const cell *params)
char *name;
proplist *item,*pred;
(void)amx;
cstr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cstr);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],&pred);
if (item!=NULL) {
@ -401,15 +417,13 @@ static cell AMX_NATIVE_CALL delproperty(AMX *amx,const cell *params)
return prev;
}
/* existproperty(id=0, const name[]="", value=cellmin) */
static cell AMX_NATIVE_CALL existproperty(AMX *amx,const cell *params)
{
cell *cstr;
char *name;
proplist *item;
(void)amx;
cstr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cstr);
name=MakePackedString(cstr);
item=list_finditem(&proproot,params[1],name,params[3],NULL);
free(name);
@ -485,12 +499,12 @@ const AMX_NATIVE_INFO core_Natives[] = {
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_CoreInit(AMX *amx)
int AMXEXPORT amx_CoreInit(AMX *amx)
{
return amx_Register(amx, core_Natives, -1);
}
int AMXEXPORT AMXAPI amx_CoreCleanup(AMX *amx)
int AMXEXPORT amx_CoreCleanup(AMX *amx)
{
(void)amx;
#if !defined AMX_NOPROPLIST

View File

@ -1,20 +1,24 @@
/* Text file I/O module for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2003-2016
* Copyright (c) ITB CompuPhase, 2003-2006
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* http://www.apache.org/licenses/LICENSE-2.0
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxfile.c 5588 2016-10-25 11:13:28Z $
* Version: $Id: amxfile.c 3660 2006-11-05 13:05:09Z thiadmer $
*/
#if defined _UNICODE || defined __UNICODE__ || defined UNICODE
@ -26,116 +30,53 @@
# endif
#endif
#include <assert.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "osdefs.h"
#if (defined __linux || defined __linux__) && !defined __LINUX__
#define __LINUX__
#endif
#if defined FREEBSD && !defined __FreeBSD__
#define __FreeBSD__
#endif
#if defined __BORLANDC__
#include <dir.h>
#endif
#if defined __BORLANDC__ || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined MACOS || defined __APPLE__
#include <utime.h>
#else
#include <sys/utime.h>
#endif
#if defined __WIN32__ || defined __MSDOS__
#include <assert.h>
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined __MSDOS__
#include <io.h>
#include <malloc.h>
#endif
#if defined __WATCOMC__ || defined _MSC_VER
#include <direct.h>
#endif
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined MACOS || defined __APPLE__
#include <dirent.h>
#else
#include <io.h>
#endif
#if defined __GNUC__ || defined __clang__
#include <unistd.h>
#endif
#include "amx.h"
#if defined __WIN32__ || defined _Windows
#if defined __WIN32__ || defined _WIN32 || defined WIN32 || defined _Windows
#include <windows.h>
#endif
#if defined LINUX || defined __FreeBSD__ || defined __OpenBSD__ || defined MACOS
#include <dirent.h>
#endif
#include "osdefs.h"
#include "amx.h"
#include "fpattern.c"
#if !defined AMXFILE_VAR
#define AMXFILE_VAR "AMXFILE"
#endif
#if !defined sizearray
#define sizearray(a) (sizeof(a)/sizeof((a)[0]))
#elif AMXFILE_VAR==""
#undef AMXFILE_VAR
#endif
#if defined _UNICODE
#include <tchar.h>
# include <tchar.h>
#elif !defined __T
typedef char TCHAR;
#define __T(string) string
#define _tchmod chmod
#define _tcscat strcat
#define _tcschr strchr
#define _tcscmp strcmp
#define _tcscpy strcpy
#define _tcsdup strdup
#define _tcslen strlen
#define _tcsncpy strncpy
#define _tcsnicmp strnicmp
#define _tcspbrk strpbrk
#define _tcsrchr strrchr
#define _tcstol strtol
#define _tfopen fopen
#define _tfputs fputs
#define _tgetenv getenv
#define _tremove remove
#define _trename rename
#if defined __BORLANDC__ || defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined MACOS || defined __APPLE__
#define _tmkdir mkdir
#define _trmdir rmdir
#define _tstat stat
#define _tutime utime
#else
#define _tmkdir _mkdir
#define _trmdir _rmdir
#define _tstat _stat
#define _tstat64 _stat64
#define _tutime _utime
#endif
#if defined __APPLE__
#define t_stat stat
#elif defined __WIN32__
#if defined __WATCOMC__
#define t_stat __stat
#else
#define t_stat _stat
#endif
#else
#define t_stat stat
#endif
#endif
#if !defined t_stat
#if defined _tstat
#define t_stat _tstat
#else
#define t_stat stat
#endif
#endif
#if !defined S_ISDIR
#define S_ISDIR(mode) (((mode) & _S_IFDIR) != 0)
# define __T(string) string
# define _tfopen fopen
# define _tgetenv getenv
# define _tfputs fputs
# define _tcscat strcat
# define _tcschr strchr
# define _tcscpy strcpy
# define _tcsdup strdup
# define _tcslen strlen
# define _tcsncpy strncpy
# define _tcspbrk strpbrk
# define _tcsrchr strrchr
#endif
#include "minIni.c"
#if !defined UNUSED_PARAM
#define UNUSED_PARAM(p) ((void)(p))
#endif
enum filemode {
io_read, /* file must exist */
@ -363,13 +304,13 @@ static size_t fgets_char(FILE *fp, char *string, size_t max)
return index;
}
#if (defined __WIN32__ || defined _WIN32 || defined WIN32) && _MSC_VER < 1500
#if defined __WIN32__ || defined _WIN32 || defined WIN32
#if defined _UNICODE
wchar_t *_wgetenv(wchar_t *name)
{
static wchar_t buffer[_MAX_PATH];
buffer[0]=L'\0';
GetEnvironmentVariable(name,buffer,sizearray(buffer));
GetEnvironmentVariable(name,buffer,sizeof buffer/sizeof(wchar_t));
return buffer[0]!=L'\0' ? buffer : NULL;
}
#else
@ -377,7 +318,7 @@ char *getenv(const char *name)
{
static char buffer[_MAX_PATH];
buffer[0]='\0';
GetEnvironmentVariable(name,buffer,sizearray(buffer));
GetEnvironmentVariable(name,buffer,sizeof buffer);
return buffer[0]!='\0' ? buffer : NULL;
}
#endif
@ -488,7 +429,6 @@ static cell AMX_NATIVE_CALL n_fopen(AMX *amx, const cell *params)
TCHAR *name,fullname[_MAX_PATH];
FILE *f = NULL;
(void)amx;
altattrib=NULL;
switch (params[2] & 0x7fff) {
case io_read:
@ -510,7 +450,7 @@ static cell AMX_NATIVE_CALL n_fopen(AMX *amx, const cell *params)
/* get the filename */
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL) {
f=_tfopen(fullname,attrib);
if (f==NULL && altattrib!=NULL)
f=_tfopen(fullname,altattrib);
@ -521,20 +461,19 @@ static cell AMX_NATIVE_CALL n_fopen(AMX *amx, const cell *params)
/* fclose(File: handle) */
static cell AMX_NATIVE_CALL n_fclose(AMX *amx, const cell *params)
{
(void)amx;
UNUSED_PARAM(amx);
return fclose((FILE*)params[1]) == 0;
}
/* fwrite(File: handle, const string[]) */
static cell AMX_NATIVE_CALL n_fwrite(AMX *amx, const cell *params)
{
size_t r = 0;
int r = 0;
cell *cptr;
char *str;
int len;
(void)amx;
cptr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cptr);
amx_StrLen(cptr,&len);
if (len==0)
return 0;
@ -549,14 +488,13 @@ static cell AMX_NATIVE_CALL n_fwrite(AMX *amx, const cell *params)
/* the string is unpacked, write it as UTF-8 */
r=fputs_cell((FILE*)params[1],cptr,1);
} /* if */
return (cell)r;
return r;
}
/* fread(File: handle, string[], size=sizeof string, bool:pack=false) */
static cell AMX_NATIVE_CALL n_fread(AMX *amx, const cell *params)
{
size_t chars;
int max;
int chars,max;
char *str;
cell *cptr;
@ -566,7 +504,7 @@ static cell AMX_NATIVE_CALL n_fread(AMX *amx, const cell *params)
if (params[4])
max*=sizeof(cell);
cptr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cptr);
str=(char *)alloca(max);
if (str==NULL || cptr==NULL) {
amx_RaiseError(amx, AMX_ERR_NATIVE);
@ -576,15 +514,15 @@ static cell AMX_NATIVE_CALL n_fread(AMX *amx, const cell *params)
if (params[4]) {
/* store as packed string, read an ASCII/ANSI string */
chars=fgets_char((FILE*)params[1],str,max);
assert((int)chars<max);
amx_SetString(cptr,str,1,0,max);
assert(chars<max);
amx_SetString(cptr,str,(int)params[4],0,max);
} else {
/* store and unpacked string, interpret UTF-8 */
chars=fgets_cell((FILE*)params[1],cptr,max,1);
} /* if */
assert((int)chars<max);
return (cell)chars;
assert(chars<max);
return chars;
}
/* fputchar(File: handle, value, bool:utf8 = true) */
@ -592,7 +530,7 @@ static cell AMX_NATIVE_CALL n_fputchar(AMX *amx, const cell *params)
{
size_t result;
(void)amx;
UNUSED_PARAM(amx);
if (params[3]) {
cell str[2];
str[0]=params[2];
@ -600,10 +538,9 @@ static cell AMX_NATIVE_CALL n_fputchar(AMX *amx, const cell *params)
result=fputs_cell((FILE*)params[1],str,1);
} else {
fputc((int)params[2],(FILE*)params[1]);
result=1;
} /* if */
assert(result==0 || result==1);
return (cell)result;
return result;
}
/* fgetchar(File: handle, bool:utf8 = true) */
@ -612,7 +549,7 @@ static cell AMX_NATIVE_CALL n_fgetchar(AMX *amx, const cell *params)
cell str[2];
size_t result;
(void)amx;
UNUSED_PARAM(amx);
if (params[2]) {
result=fgets_cell((FILE*)params[1],str,2,1);
} else {
@ -640,10 +577,9 @@ static cell AMX_NATIVE_CALL n_fgetchar(AMX *amx, const cell *params)
static cell AMX_NATIVE_CALL n_fblockwrite(AMX *amx, const cell *params)
{
cell *cptr;
cell count=0;
cell count;
(void)amx;
cptr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cptr);
if (cptr!=NULL) {
cell max=params[3];
ucell v;
@ -660,10 +596,9 @@ static cell AMX_NATIVE_CALL n_fblockwrite(AMX *amx, const cell *params)
static cell AMX_NATIVE_CALL n_fblockread(AMX *amx, const cell *params)
{
cell *cptr;
cell count=0;
cell count;
(void)amx;
cptr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cptr);
if (cptr!=NULL) {
cell max=params[3];
ucell v;
@ -679,8 +614,8 @@ static cell AMX_NATIVE_CALL n_fblockread(AMX *amx, const cell *params)
/* File: ftemp() */
static cell AMX_NATIVE_CALL n_ftemp(AMX *amx, const cell *params)
{
(void)amx;
(void)params;
UNUSED_PARAM(amx);
UNUSED_PARAM(params);
return (cell)tmpfile();
}
@ -688,7 +623,6 @@ static cell AMX_NATIVE_CALL n_ftemp(AMX *amx, const cell *params)
static cell AMX_NATIVE_CALL n_fseek(AMX *amx, const cell *params)
{
int whence;
(void)amx;
switch (params[3]) {
case seek_start:
whence=SEEK_SET;
@ -704,6 +638,7 @@ static cell AMX_NATIVE_CALL n_fseek(AMX *amx, const cell *params)
default:
return 0;
} /* switch */
UNUSED_PARAM(amx);
return lseek(fileno((FILE*)params[1]),params[2],whence);
}
@ -713,61 +648,9 @@ static cell AMX_NATIVE_CALL n_fremove(AMX *amx, const cell *params)
int r=1;
TCHAR *name,fullname[_MAX_PATH];
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
/* if this is a directory, try _trmdir() */
#if defined _WIN64
struct __stat64 stbuf;
_tstat64(fullname, &stbuf);
#else
struct t_stat stbuf;
_tstat(fullname, &stbuf);
#endif
if (S_ISDIR(stbuf.st_mode))
r=_trmdir(fullname);
else
r=_tremove(fullname);
} /* if */
return r==0;
}
/* bool: fcopy(const source[], const target[]) */
static cell AMX_NATIVE_CALL n_fcopy(AMX *amx, const cell *params)
{
int r=1;
TCHAR *name,oldname[_MAX_PATH],newname[_MAX_PATH];
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(oldname,name,sizearray(oldname))!=NULL) {
amx_StrParam(amx,params[2],name);
if (name!=NULL && completename(newname,name,sizearray(newname))!=NULL) {
#if defined __WIN32__
r= CopyFile(oldname,newname,FALSE)==FALSE;
#else
TCHAR cmd[2*_MAX_PATH + 10];
sprintf(cmd,"cp %s %s",oldname,newname);
r= system(cmd)<0;
#endif
} /* if */
} /* if */
return r==0;
}
/* bool: frename(const oldname[], const newname[]) */
static cell AMX_NATIVE_CALL n_frename(AMX *amx, const cell *params)
{
int r=1;
TCHAR *name,oldname[_MAX_PATH],newname[_MAX_PATH];
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(oldname,name,sizearray(oldname))!=NULL) {
amx_StrParam(amx,params[2],name);
if (name!=NULL && completename(newname,name,sizearray(newname))!=NULL)
r=_trename(oldname,newname);
} /* if */
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL)
r=remove(fullname);
return r==0;
}
@ -779,7 +662,7 @@ static cell AMX_NATIVE_CALL n_flength(AMX *amx, const cell *params)
c=lseek(fn,0,SEEK_CUR); /* save the current position */
l=lseek(fn,0,SEEK_END); /* return the file position at its end */
lseek(fn,c,SEEK_SET); /* restore the file pointer */
(void)amx;
UNUSED_PARAM(amx);
return l;
}
@ -830,10 +713,10 @@ static int matchfiles(const TCHAR *path,int skip,TCHAR *out,int outlen)
#else
/* copy directory part only (zero-terminate) */
if (basename==path) {
_tcscpy(dirname,".");
strcpy(dirname,".");
} else {
_tcsncpy(dirname,path,(int)(basename-path));
dirname[(int)(basename-path)]=__T('\0');
strncpy(dirname,path,(int)(basename-path));
dirname[(int)(basename-path)]=_T('\0');
} /* if */
if ((dir=opendir(dirname))!=NULL) {
while ((entry=readdir(dir))!=NULL) {
@ -855,9 +738,8 @@ static cell AMX_NATIVE_CALL n_fexist(AMX *amx, const cell *params)
int r=0;
TCHAR *name,fullname[_MAX_PATH];
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL)
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL)
r=matchfiles(fullname,0,NULL,0);
return r;
}
@ -868,361 +750,48 @@ static cell AMX_NATIVE_CALL n_fmatch(AMX *amx, const cell *params)
TCHAR *name,fullname[_MAX_PATH]="";
cell *cptr;
(void)amx;
amx_StrParam(amx,params[2],name);
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
if (!matchfiles(fullname,params[3],fullname,sizearray(fullname))) {
if (name!=NULL && completename(fullname,name,sizeof fullname)!=NULL) {
if (!matchfiles(fullname,params[3],fullname,sizeof fullname)) {
fullname[0]='\0';
} else {
/* copy the string into the destination */
cptr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cptr);
amx_SetString(cptr,fullname,1,0,params[4]);
} /* if */
} /* if */
return fullname[0]!='\0';
}
/* bool: fstat(const name[], &size = 0, &timestamp = 0, &attrib = 0, &inode = 0) */
static cell AMX_NATIVE_CALL n_fstat(AMX *amx, const cell *params)
{
TCHAR *name,fullname[_MAX_PATH]="";
cell *cptr;
int result=0;
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
int err;
#if defined _WIN64
struct __stat64 stbuf;
err = _tstat64(fullname, &stbuf);
#else
struct t_stat stbuf;
err = _tstat(fullname, &stbuf);
#endif
if (err == 0) {
cptr=amx_Address(amx,params[2]);
*cptr=(cell)stbuf.st_size;
cptr=amx_Address(amx,params[3]);
*cptr=(cell)stbuf.st_mtime;
cptr=amx_Address(amx,params[4]);
*cptr=stbuf.st_mode; /* mode/protection bits */
cptr=amx_Address(amx,params[5]);
*cptr=stbuf.st_ino; /* inode number, unique id for a file */
result=1;
} /* if */
} /* if */
return result;
}
/* bool: fattrib(const name[], timestamp=0, attrib=0x0f) */
static cell AMX_NATIVE_CALL n_fattrib(AMX *amx, const cell *params)
{
#if !(defined __WIN32__ || defined _WIN32 || defined WIN32) || defined __BORLANDC__
#define _utime(n,t) utime(n,t)
#define _utimbuf utimbuf
#endif
TCHAR *name,fullname[_MAX_PATH]="";
int result=0;
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
result=1;
if (params[2]!=0) {
struct _utimbuf times;
times.actime=(unsigned long)params[2];
times.modtime=(unsigned long)params[2];
result=result && (_tutime(name,&times)==0);
} /* if */
if (params[3]!=0x0f)
result=result && (_tchmod(name,(int)params[3])==0);
} /* if */
return result;
}
/* bool: fcreatedir(const name[]) */
static cell AMX_NATIVE_CALL n_fcreatedir(AMX *amx, const cell *params)
{
TCHAR *name,fullname[_MAX_PATH]="";
int r=1;
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
#if defined __WIN32__ || defined __DOS__
r=_tmkdir(fullname);
#else
r=_tmkdir(fullname,0755);
#endif
} /* if */
return r==0;
}
/* CRC32 functions are adapted from source code from www.networkdls.com
* The table generation routines are replaced by a hard-coded table, which
* can be stored in Flash ROM.
*/
const unsigned long ulCRCTable[256] = // CRC Lookup Table Array
{
0x00000000Lu, 0x77073096Lu, 0xee0e612cLu, 0x990951baLu,
0x076dc419Lu, 0x706af48fLu, 0xe963a535Lu, 0x9e6495a3Lu,
0x0edb8832Lu, 0x79dcb8a4Lu, 0xe0d5e91eLu, 0x97d2d988Lu,
0x09b64c2bLu, 0x7eb17cbdLu, 0xe7b82d07Lu, 0x90bf1d91Lu,
0x1db71064Lu, 0x6ab020f2Lu, 0xf3b97148Lu, 0x84be41deLu,
0x1adad47dLu, 0x6ddde4ebLu, 0xf4d4b551Lu, 0x83d385c7Lu,
0x136c9856Lu, 0x646ba8c0Lu, 0xfd62f97aLu, 0x8a65c9ecLu,
0x14015c4fLu, 0x63066cd9Lu, 0xfa0f3d63Lu, 0x8d080df5Lu,
0x3b6e20c8Lu, 0x4c69105eLu, 0xd56041e4Lu, 0xa2677172Lu,
0x3c03e4d1Lu, 0x4b04d447Lu, 0xd20d85fdLu, 0xa50ab56bLu,
0x35b5a8faLu, 0x42b2986cLu, 0xdbbbc9d6Lu, 0xacbcf940Lu,
0x32d86ce3Lu, 0x45df5c75Lu, 0xdcd60dcfLu, 0xabd13d59Lu,
0x26d930acLu, 0x51de003aLu, 0xc8d75180Lu, 0xbfd06116Lu,
0x21b4f4b5Lu, 0x56b3c423Lu, 0xcfba9599Lu, 0xb8bda50fLu,
0x2802b89eLu, 0x5f058808Lu, 0xc60cd9b2Lu, 0xb10be924Lu,
0x2f6f7c87Lu, 0x58684c11Lu, 0xc1611dabLu, 0xb6662d3dLu,
0x76dc4190Lu, 0x01db7106Lu, 0x98d220bcLu, 0xefd5102aLu,
0x71b18589Lu, 0x06b6b51fLu, 0x9fbfe4a5Lu, 0xe8b8d433Lu,
0x7807c9a2Lu, 0x0f00f934Lu, 0x9609a88eLu, 0xe10e9818Lu,
0x7f6a0dbbLu, 0x086d3d2dLu, 0x91646c97Lu, 0xe6635c01Lu,
0x6b6b51f4Lu, 0x1c6c6162Lu, 0x856530d8Lu, 0xf262004eLu,
0x6c0695edLu, 0x1b01a57bLu, 0x8208f4c1Lu, 0xf50fc457Lu,
0x65b0d9c6Lu, 0x12b7e950Lu, 0x8bbeb8eaLu, 0xfcb9887cLu,
0x62dd1ddfLu, 0x15da2d49Lu, 0x8cd37cf3Lu, 0xfbd44c65Lu,
0x4db26158Lu, 0x3ab551ceLu, 0xa3bc0074Lu, 0xd4bb30e2Lu,
0x4adfa541Lu, 0x3dd895d7Lu, 0xa4d1c46dLu, 0xd3d6f4fbLu,
0x4369e96aLu, 0x346ed9fcLu, 0xad678846Lu, 0xda60b8d0Lu,
0x44042d73Lu, 0x33031de5Lu, 0xaa0a4c5fLu, 0xdd0d7cc9Lu,
0x5005713cLu, 0x270241aaLu, 0xbe0b1010Lu, 0xc90c2086Lu,
0x5768b525Lu, 0x206f85b3Lu, 0xb966d409Lu, 0xce61e49fLu,
0x5edef90eLu, 0x29d9c998Lu, 0xb0d09822Lu, 0xc7d7a8b4Lu,
0x59b33d17Lu, 0x2eb40d81Lu, 0xb7bd5c3bLu, 0xc0ba6cadLu,
0xedb88320Lu, 0x9abfb3b6Lu, 0x03b6e20cLu, 0x74b1d29aLu,
0xead54739Lu, 0x9dd277afLu, 0x04db2615Lu, 0x73dc1683Lu,
0xe3630b12Lu, 0x94643b84Lu, 0x0d6d6a3eLu, 0x7a6a5aa8Lu,
0xe40ecf0bLu, 0x9309ff9dLu, 0x0a00ae27Lu, 0x7d079eb1Lu,
0xf00f9344Lu, 0x8708a3d2Lu, 0x1e01f268Lu, 0x6906c2feLu,
0xf762575dLu, 0x806567cbLu, 0x196c3671Lu, 0x6e6b06e7Lu,
0xfed41b76Lu, 0x89d32be0Lu, 0x10da7a5aLu, 0x67dd4accLu,
0xf9b9df6fLu, 0x8ebeeff9Lu, 0x17b7be43Lu, 0x60b08ed5Lu,
0xd6d6a3e8Lu, 0xa1d1937eLu, 0x38d8c2c4Lu, 0x4fdff252Lu,
0xd1bb67f1Lu, 0xa6bc5767Lu, 0x3fb506ddLu, 0x48b2364bLu,
0xd80d2bdaLu, 0xaf0a1b4cLu, 0x36034af6Lu, 0x41047a60Lu,
0xdf60efc3Lu, 0xa867df55Lu, 0x316e8eefLu, 0x4669be79Lu,
0xcb61b38cLu, 0xbc66831aLu, 0x256fd2a0Lu, 0x5268e236Lu,
0xcc0c7795Lu, 0xbb0b4703Lu, 0x220216b9Lu, 0x5505262fLu,
0xc5ba3bbeLu, 0xb2bd0b28Lu, 0x2bb45a92Lu, 0x5cb36a04Lu,
0xc2d7ffa7Lu, 0xb5d0cf31Lu, 0x2cd99e8bLu, 0x5bdeae1dLu,
0x9b64c2b0Lu, 0xec63f226Lu, 0x756aa39cLu, 0x026d930aLu,
0x9c0906a9Lu, 0xeb0e363fLu, 0x72076785Lu, 0x05005713Lu,
0x95bf4a82Lu, 0xe2b87a14Lu, 0x7bb12baeLu, 0x0cb61b38Lu,
0x92d28e9bLu, 0xe5d5be0dLu, 0x7cdcefb7Lu, 0x0bdbdf21Lu,
0x86d3d2d4Lu, 0xf1d4e242Lu, 0x68ddb3f8Lu, 0x1fda836eLu,
0x81be16cdLu, 0xf6b9265bLu, 0x6fb077e1Lu, 0x18b74777Lu,
0x88085ae6Lu, 0xff0f6a70Lu, 0x66063bcaLu, 0x11010b5cLu,
0x8f659effLu, 0xf862ae69Lu, 0x616bffd3Lu, 0x166ccf45Lu,
0xa00ae278Lu, 0xd70dd2eeLu, 0x4e048354Lu, 0x3903b3c2Lu,
0xa7672661Lu, 0xd06016f7Lu, 0x4969474dLu, 0x3e6e77dbLu,
0xaed16a4aLu, 0xd9d65adcLu, 0x40df0b66Lu, 0x37d83bf0Lu,
0xa9bcae53Lu, 0xdebb9ec5Lu, 0x47b2cf7fLu, 0x30b5ffe9Lu,
0xbdbdf21cLu, 0xcabac28aLu, 0x53b39330Lu, 0x24b4a3a6Lu,
0xbad03605Lu, 0xcdd70693Lu, 0x54de5729Lu, 0x23d967bfLu,
0xb3667a2eLu, 0xc4614ab8Lu, 0x5d681b02Lu, 0x2a6f2b94Lu,
0xb40bbe37Lu, 0xc30c8ea1Lu, 0x5a05df1bLu, 0x2d02ef8dLu
};
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// This function uses the ulCRCTable lookup table to generate a CRC for xData
static unsigned long PartialCRC(unsigned long ulCRC, unsigned char *sBuf, unsigned long lBufSz)
{
while(lBufSz--)
ulCRC = (ulCRC >> 8) ^ ulCRCTable[(ulCRC & 0xFF) ^ *sBuf++];
return ulCRC;
}
/* filecrc(const name[]) */
static cell AMX_NATIVE_CALL n_filecrc(AMX *amx, const cell *params)
{
TCHAR *name,fullname[_MAX_PATH]="";
FILE *fp;
unsigned char buffer[256];
unsigned long ulCRC = 0xffffffff;
size_t numread;
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL
&& (fp=_tfopen(fullname,"rb"))!=NULL)
{
do {
numread=fread(buffer,sizeof(unsigned char),sizeof buffer,fp);
ulCRC=PartialCRC(ulCRC,buffer,(unsigned long)numread);
} while(numread==sizeof buffer);
fclose(fp);
} /* if */
return(ulCRC ^ 0xffffffff);
}
const TCHAR default_ini_name[] = "config.ini";
/* readcfg(const filename[]="", const section[]="", const key[], value[], size=sizeof value, const defvalue[]="", bool:packed=false) */
static cell AMX_NATIVE_CALL n_readcfg(AMX *amx, const cell *params)
{
TCHAR *name,fullname[_MAX_PATH]="";
TCHAR *section,*key,*defvalue;
TCHAR *buffer;
int size,result=0;
cell *cptr;
size=(int)params[5];
if (size<=0)
return 0;
if (params[7])
size*=sizeof(cell);
amx_StrParam(amx,params[1],name);
if (name!=NULL && *name=='\0')
name=(TCHAR*)default_ini_name;
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
amx_StrParam(amx,params[2],section);
amx_StrParam(amx,params[3],key);
amx_StrParam(amx,params[6],defvalue);
cptr=amx_Address(amx,params[4]);
buffer=(char *)alloca(size);
if (buffer==NULL || cptr==NULL) {
amx_RaiseError(amx, AMX_ERR_NATIVE);
return 0;
} /* if */
result=ini_gets(section,key,defvalue,buffer,size,fullname);
amx_SetString(cptr,buffer,params[7],0,size);
} /* if */
return result;
}
/* readcfgvalue(const filename[]="", const section[]="", const key[], defvalue=0) */
static cell AMX_NATIVE_CALL n_readcfgvalue(AMX *amx, const cell *params)
{
TCHAR *name,fullname[_MAX_PATH]="";
TCHAR *section,*key;
long result=0;
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && *name=='\0')
name=(TCHAR*)default_ini_name;
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
amx_StrParam(amx,params[2],section);
amx_StrParam(amx,params[3],key);
result=ini_getl(section,key,(long)params[4],fullname);
} /* if */
return result;
}
/* writecfg(const filename[]="", const section[]="", const key[], const value[]) */
static cell AMX_NATIVE_CALL n_writecfg(AMX *amx, const cell *params)
{
TCHAR *name,fullname[_MAX_PATH]="";
TCHAR *section,*key,*value;
int result=0;
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && *name=='\0')
name=(TCHAR*)default_ini_name;
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
amx_StrParam(amx,params[2],section);
amx_StrParam(amx,params[3],key);
amx_StrParam(amx,params[4],value);
result=ini_puts(section,key,value,fullname);
} /* if */
return result;
}
/* writecfgvalue(const filename[]="", const section[]="", const key[], value) */
static cell AMX_NATIVE_CALL n_writecfgvalue(AMX *amx, const cell *params)
{
TCHAR *name,fullname[_MAX_PATH]="";
TCHAR *section,*key;
int result=0;
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && *name=='\0')
name=(TCHAR*)default_ini_name;
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
amx_StrParam(amx,params[2],section);
amx_StrParam(amx,params[3],key);
result=ini_putl(section,key,(long)params[4],fullname);
} /* if */
return result;
}
/* deletecfg(const filename[]="", const section[]="", const key[]="") */
static cell AMX_NATIVE_CALL n_deletecfg(AMX *amx, const cell *params)
{
TCHAR *name,fullname[_MAX_PATH]="";
TCHAR *section,*key;
int result=0;
(void)amx;
amx_StrParam(amx,params[1],name);
if (name!=NULL && *name=='\0')
name=(TCHAR*)default_ini_name;
if (name!=NULL && completename(fullname,name,sizearray(fullname))!=NULL) {
amx_StrParam(amx,params[2],section);
if (section!=NULL && *section=='\0')
section=NULL;
amx_StrParam(amx,params[3],key);
if (key!=NULL && *key=='\0')
key=NULL;
result=ini_puts(section,key,NULL,fullname);
} /* if */
return result;
}
#if defined __cplusplus
extern "C"
#endif
AMX_NATIVE_INFO file_Natives[] = {
{ "fopen", n_fopen },
{ "fclose", n_fclose },
{ "fwrite", n_fwrite },
{ "fread", n_fread },
{ "fputchar", n_fputchar },
{ "fgetchar", n_fgetchar },
{ "fblockwrite", n_fblockwrite },
{ "fblockread", n_fblockread },
{ "ftemp", n_ftemp },
{ "fseek", n_fseek },
{ "flength", n_flength },
{ "fremove", n_fremove },
{ "fcopy", n_fcopy },
{ "frename", n_frename },
{ "fexist", n_fexist },
{ "fmatch", n_fmatch },
{ "fstat", n_fstat },
{ "fattrib", n_fattrib },
{ "filecrc", n_filecrc },
{ "fcreatedir", n_fcreatedir },
{ "readcfg", n_readcfg },
{ "readcfgvalue", n_readcfgvalue },
{ "writecfg", n_writecfg },
{ "writecfgvalue",n_writecfgvalue },
{ "deletecfg", n_deletecfg },
{ "fopen", n_fopen },
{ "fclose", n_fclose },
{ "fwrite", n_fwrite },
{ "fread", n_fread },
{ "fputchar", n_fputchar },
{ "fgetchar", n_fgetchar },
{ "fblockwrite", n_fblockwrite },
{ "fblockread", n_fblockread },
{ "ftemp", n_ftemp },
{ "fseek", n_fseek },
{ "flength", n_flength },
{ "fremove", n_fremove },
{ "fexist", n_fexist },
{ "fmatch", n_fmatch },
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_FileInit(AMX *amx)
int AMXEXPORT amx_FileInit(AMX *amx)
{
return amx_Register(amx, file_Natives, -1);
}
int AMXEXPORT AMXAPI amx_FileCleanup(AMX *amx)
int AMXEXPORT amx_FileCleanup(AMX *amx)
{
(void)amx;
UNUSED_PARAM(amx);
return AMX_ERR_NONE;
}

View File

@ -1,20 +1,24 @@
/* String functions for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2005-2016
* Copyright (c) ITB CompuPhase, 2005-2006
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* http://www.apache.org/licenses/LICENSE-2.0
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxstring.c 5514 2016-05-20 14:26:51Z $
* Version: $Id: amxstring.c 3656 2006-10-24 07:20:26Z thiadmer $
*/
#include <limits.h>
@ -48,14 +52,11 @@
#if !defined isdigit
# define isdigit(c) ((unsigned)((c)-'0')<10u)
#endif
#if !defined sizearray
# define sizearray(a) (sizeof(a) / sizeof((a)[0]))
#endif
/* dest the destination buffer; the buffer must point to the start of a cell
* source the source buffer, this must be aligned to a cell edge
* len the number of characters (bytes) to copy, excluding the zero terminator
* len the number of characters (bytes) to copy
* offs the offset in dest, in characters (bytes)
*/
static int amx_StrPack(cell *dest,cell *source,int len,int offs)
@ -126,10 +127,6 @@ static int amx_StrPack(cell *dest,cell *source,int len,int offs)
return AMX_ERR_NONE;
}
/* dest the destination buffer, this must be aligned to a cell edge
* source the source buffer, it must point to the start of a cell
* len the number of cells to copy, excluding the zero terminator
*/
static int amx_StrUnpack(cell *dest,cell *source,int len)
{
/* len excludes the terminating '\0' byte */
@ -183,6 +180,17 @@ static cell extractchar(cell *string,int index,int mklower)
return c;
}
static int verify_addr(AMX *amx,cell addr)
{
int err;
cell *cdest;
err=amx_GetAddr(amx,addr,&cdest);
if (err!=AMX_ERR_NONE)
amx_RaiseError(amx,err);
return err;
}
/* strlen(const string[])
*/
static cell AMX_NATIVE_CALL n_strlen(AMX *amx,const cell *params)
@ -190,9 +198,8 @@ static cell AMX_NATIVE_CALL n_strlen(AMX *amx,const cell *params)
cell *cptr;
int len = 0;
(void)(amx);
cptr=amx_Address(amx,params[1]);
amx_StrLen(cptr,&len);
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
amx_StrLen(cptr,&len);
return len;
}
@ -201,14 +208,21 @@ static cell AMX_NATIVE_CALL n_strlen(AMX *amx,const cell *params)
static cell AMX_NATIVE_CALL n_strpack(AMX *amx,const cell *params)
{
cell *cdest,*csrc;
int len,err;
int len,needed,err;
size_t lastaddr;
csrc=amx_Address(amx,params[2]);
/* calculate number of cells needed for (packed) destination */
amx_GetAddr(amx,params[2],&csrc);
amx_StrLen(csrc,&len);
if ((unsigned)len>params[3]*sizeof(cell)-1)
len=params[3]*sizeof(cell)-1;
needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */
assert(needed>0);
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
cdest=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cdest);
err=amx_StrPack(cdest,csrc,len,0);
if (err!=AMX_ERR_NONE)
return amx_RaiseError(amx,err);
@ -222,14 +236,19 @@ static cell AMX_NATIVE_CALL n_strunpack(AMX *amx,const cell *params)
{
cell *cdest,*csrc;
int len,err;
size_t lastaddr;
csrc=amx_Address(amx,params[2]);
/* calculate number of cells needed for (unpacked) destination */
amx_GetAddr(amx,params[2],&csrc);
amx_StrLen(csrc,&len);
assert(len>=0);
if (len>=params[3])
len=params[3]-1;
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+1)-1);
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
cdest=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cdest);
err=amx_StrUnpack(cdest,csrc,len);
if (err!=AMX_ERR_NONE)
return amx_RaiseError(amx,err);
@ -244,22 +263,29 @@ static cell AMX_NATIVE_CALL n_strunpack(AMX *amx,const cell *params)
static cell AMX_NATIVE_CALL n_strcat(AMX *amx,const cell *params)
{
cell *cdest,*csrc;
int len,len2;
int len,len2,needed;
int packed,err;
size_t lastaddr;
/* calculate number of cells needed for (packed) destination */
csrc=amx_Address(amx,params[2]);
cdest=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[2],&csrc);
amx_GetAddr(amx,params[1],&cdest);
amx_StrLen(csrc,&len);
amx_StrLen(cdest,&len2);
packed=(*cdest==0) ? ((ucell)*csrc>UNPACKEDMAX) : ((ucell)*cdest>UNPACKEDMAX);
if (packed) {
if ((unsigned)(len+len2)>params[3]*sizeof(cell)-1)
len=params[3]*sizeof(cell)-len2-1;
needed=(len+len2+sizeof(cell))/sizeof(cell); /* # of cells needed */
assert(needed>0);
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
} else {
if (len+len2>params[3]-1)
len=params[3]-len2-1;
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+len2+1)-1);
} /* if */
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
if (packed) {
err=amx_StrPack(cdest,csrc,len,len2);
@ -274,37 +300,6 @@ static cell AMX_NATIVE_CALL n_strcat(AMX *amx,const cell *params)
return len;
}
/* strcopy(dest[], const source[], maxlength=sizeof dest)
* packed/unpacked attribute from source[]
*/
static cell AMX_NATIVE_CALL n_strcopy(AMX *amx,const cell *params)
{
cell *cdest,*csrc;
int len,packed,err;
/* calculate number of cells needed for (packed) destination */
csrc=amx_Address(amx,params[2]);
cdest=amx_Address(amx,params[1]);
amx_StrLen(csrc,&len);
packed=(ucell)*csrc>UNPACKEDMAX;
if (packed) {
if ((unsigned)len>params[3]*sizeof(cell)-1)
len=params[3]*sizeof(cell)-1;
} else {
if (len>params[3]-1)
len=params[3]-1;
} /* if */
if (packed)
err=amx_StrPack(cdest,csrc,len,0);
else
err=amx_StrUnpack(cdest,csrc,len);
if (err!=AMX_ERR_NONE)
return amx_RaiseError(amx,err);
return len;
}
static int compare(cell *cstr1,cell *cstr2,int ignorecase,int length,int offs1)
{
int index;
@ -333,9 +328,8 @@ static cell AMX_NATIVE_CALL n_strcmp(AMX *amx,const cell *params)
int len1,len2,len;
cell result;
(void)(amx);
cstr1=amx_Address(amx,params[1]);
cstr2=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[1],&cstr1);
amx_GetAddr(amx,params[2],&cstr2);
/* get the maximum length to compare */
amx_StrLen(cstr1,&len1);
@ -345,16 +339,12 @@ static cell AMX_NATIVE_CALL n_strcmp(AMX *amx,const cell *params)
len=len2;
if (len>params[4])
len=params[4];
if (len==0) {
if (params[4]==0 || len1==len2)
result=0;
else
result=(len1<len2) ? -1 : 1;
} else {
result=compare(cstr1,cstr2,params[3],len,0);
if (result==0 && len!=params[4] && len1!=len2)
result=(len1<len2) ? -1 : 1;
}
if (len==0)
return 0;
result=compare(cstr1,cstr2,params[3],len,0);
if (result==0 && len!=params[4])
result=len1-len2;
return result;
}
@ -366,9 +356,8 @@ static cell AMX_NATIVE_CALL n_strfind(AMX *amx,const cell *params)
int lenstr,lensub,offs;
cell c,f;
(void)(amx);
cstr=amx_Address(amx,params[1]);
csub=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[1],&cstr);
amx_GetAddr(amx,params[2],&csub);
/* get the maximum length to compare */
amx_StrLen(cstr,&lenstr);
@ -398,16 +387,17 @@ static cell AMX_NATIVE_CALL n_strfind(AMX *amx,const cell *params)
static cell AMX_NATIVE_CALL n_strmid(AMX *amx,const cell *params)
{
cell *cdest,*csrc;
int len,err;
int len,needed,err;
int soffs,doffs;
size_t lastaddr;
unsigned char *ptr;
unsigned char c;
int start=params[3];
int end=params[4];
/* calculate number of cells needed for (packed) destination */
csrc=amx_Address(amx,params[2]);
cdest=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[2],&csrc);
amx_GetAddr(amx,params[1],&cdest);
amx_StrLen(csrc,&len);
/* clamp the start/end parameters */
@ -424,10 +414,16 @@ static cell AMX_NATIVE_CALL n_strmid(AMX *amx,const cell *params)
if ((ucell)*csrc>UNPACKEDMAX) {
if ((unsigned)len>params[5]*sizeof(cell)-1)
len=params[5]*sizeof(cell)-1;
needed=(len+sizeof(cell))/sizeof(cell); /* # of cells needed */
assert(needed>0);
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
} else {
if (len>params[5]-1)
len=params[5]-1;
lastaddr=(size_t)(params[1]+sizeof(cell)*(len+1)-1);
} /* if */
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
if ((ucell)*csrc>UNPACKEDMAX) {
/* first align the source to a cell boundary */
@ -463,9 +459,8 @@ static cell AMX_NATIVE_CALL n_strdel(AMX *amx,const cell *params)
unsigned char *ptr;
unsigned char c;
(void)(amx);
/* calculate number of cells needed for (packed) destination */
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
amx_StrLen(cstr,&length);
index=(int)params[2];
offs=(int)params[3]-index;
@ -500,28 +495,34 @@ static cell AMX_NATIVE_CALL n_strdel(AMX *amx,const cell *params)
static cell AMX_NATIVE_CALL n_strins(AMX *amx,const cell *params)
{
cell *cstr,*csub;
int index,lenstr,lensub,maxlen,count;
int index,lenstr,lensub,count;
int needed;
size_t lastaddr;
unsigned char *ptr;
cell c;
/* calculate number of cells needed for (packed) destination */
cstr=amx_Address(amx,params[1]);
csub=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[1],&cstr);
amx_GetAddr(amx,params[2],&csub);
amx_StrLen(cstr,&lenstr);
amx_StrLen(csub,&lensub);
index=(int)params[3];
maxlen=(int)params[4];
if ((ucell)*cstr>UNPACKEDMAX)
maxlen*=sizeof(cell);
maxlen-=1;
if (index>lenstr || index>maxlen)
if (index>lenstr)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
if (lenstr==0) {
if (((ucell)*cstr>UNPACKEDMAX)) {
needed=(lenstr+lensub+sizeof(cell))/sizeof(cell); /* # of cells needed */
assert(needed>0);
lastaddr=(size_t)(params[1]+sizeof(cell)*needed-1);
} else {
lastaddr=(size_t)(params[1]+sizeof(cell)*(lenstr+lensub+1)-1);
} /* if */
if (verify_addr(amx,(cell)lastaddr)!=AMX_ERR_NONE)
return amx_RaiseError(amx,AMX_ERR_NATIVE);
if (*cstr==0) {
/* current string is empty (and the insertion point is zero), just make a copy */
assert(index==0);
if (lensub>maxlen)
lensub=maxlen;
if ((ucell)*csub>UNPACKEDMAX)
amx_StrPack(cstr,csub,lensub,0);
else
@ -529,12 +530,9 @@ static cell AMX_NATIVE_CALL n_strins(AMX *amx,const cell *params)
return 1;
} /* if */
lenstr+=lensub; /* length after insertion */
if (lenstr>=maxlen)
lenstr=maxlen-1;
if ((ucell)*cstr>UNPACKEDMAX) {
if (((ucell)*cstr>UNPACKEDMAX)) {
/* make room for the new characters */
for (count=lenstr; count>index; count--) {
for (count=lenstr+lensub; count>index; count--) {
ptr=packedptr(cstr,count-lensub);
c=*ptr;
ptr=packedptr(cstr,count);
@ -548,7 +546,7 @@ static cell AMX_NATIVE_CALL n_strins(AMX *amx,const cell *params)
} /* for */
} else {
/* make room for the new characters */
for (count=lenstr; count>index; count--)
for (count=lenstr+lensub; count>index; count--)
cstr[count]=cstr[count-lensub];
/* copy in the new characters */
for (count=0; count<lensub; count++) {
@ -569,9 +567,8 @@ static cell AMX_NATIVE_CALL n_strval(AMX *amx,const cell *params)
int len,negate=0;
int offset=0;
(void)(amx);
/* get parameters */
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
amx_StrLen(cstr,&len);
if ((unsigned)params[0]>=2*sizeof(cell))
offset=params[2];
@ -581,22 +578,16 @@ static cell AMX_NATIVE_CALL n_strval(AMX *amx,const cell *params)
offset=len-1;
/* skip a number of cells */
if ((ucell)*cstr>UNPACKEDMAX) {
/* packed string */
while (offset>=(int)sizeof(cell)) {
cstr++;
offset-=sizeof(cell);
len-=sizeof(cell);
} /* while */
} else {
/* unpacked string, one character per cell */
while (offset>0) {
cstr++;
offset--;
len--;
} /* while */
} /* if */
while (offset>=(int)sizeof(cell)) {
cstr++;
offset-=sizeof(cell);
len-=sizeof(cell);
} /* while */
if (len>=(int)sizeof str) {
amx_RaiseError(amx,AMX_ERR_NATIVE);
return 0;
} /* if */
amx_GetString(str,cstr,sizeof(TCHAR)>1,sizeof str);
assert(offset<(int)sizeof(cell) && offset>=0);
ptr=str+offset;
@ -622,12 +613,12 @@ static cell AMX_NATIVE_CALL n_strval(AMX *amx,const cell *params)
static cell AMX_NATIVE_CALL n_valstr(AMX *amx,const cell *params)
{
TCHAR str[50];
cell value,temp;
cell value,mult;
cell *cstr;
int len,result,negate=0;
(void)(amx);
/* find out how many digits are needed */
mult=10;
len=1;
value=params[2];
if (value<0) {
@ -635,9 +626,10 @@ static cell AMX_NATIVE_CALL n_valstr(AMX *amx,const cell *params)
len++;
value=-value;
} /* if */
for (temp=value; temp>=10; temp/=10)
while (value>=mult) {
len++;
assert(len<=sizearray(str));
mult*=10;
} /* while */
/* put in the string */
result=len;
@ -648,16 +640,16 @@ static cell AMX_NATIVE_CALL n_valstr(AMX *amx,const cell *params)
} /* while */
if (negate)
str[0]='-';
cstr=amx_Address(amx,params[1]);
amx_SetString(cstr,str,params[3],sizeof(TCHAR)>1,sizearray(str));
amx_GetAddr(amx,params[1],&cstr);
amx_SetString(cstr,str,params[3],sizeof(TCHAR)>1,UNLIMITED);
return result;
}
/* ispacked(const string[]) */
static cell AMX_NATIVE_CALL n_ispacked(AMX *amx,const cell *params)
{
cell *cstr=amx_Address(amx,params[1]);
(void)(amx);
cell *cstr;
amx_GetAddr(amx,params[1],&cstr);
return *cstr>=UNPACKEDMAX;
}
@ -736,14 +728,13 @@ static cell AMX_NATIVE_CALL n_uudecode(AMX *amx,const cell *params)
int len;
size_t size;
(void)(amx);
/* get the source */
cstr=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[2],&cstr);
amx_GetString(src,cstr,0,sizeof src);
/* decode */
len=uudecode(dst,src);
/* store */
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
size=len;
if (size>params[3]*sizeof(cell))
size=params[3]*sizeof(cell);
@ -764,14 +755,12 @@ static cell AMX_NATIVE_CALL n_uuencode(AMX *amx,const cell *params)
unsigned char src[BITMASK+2];
char dst[BITMASK+BITMASK/3+2];
(void)(amx);
/* get the source */
cstr=amx_Address(amx,params[2]);
amx_GetString((char *)src,cstr,0,sizeof src);
amx_GetAddr(amx,params[2],&cstr);
/* encode (and check for errors) */
if (uuencode(dst,src,params[3])) {
if (params[4]>0) {
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
*cstr=0;
} /* if */
return 0;
@ -780,142 +769,11 @@ static cell AMX_NATIVE_CALL n_uuencode(AMX *amx,const cell *params)
assert(strlen(dst)+1<sizeof dst);
strcat(dst,"\n");
/* store */
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
amx_SetString(cstr,dst,1,0,params[4]);
return (((params[3]+2)/3) << 2)+2;
}
/* urldecode(dest[], const source[], maxlength=sizeof dest, bool:pack=false)
* Returns the number of characters decoded; if the dest buffer is
* too small, not all bytes are stored.
* A buffer may be decoded "in-place"; the destination size is always
* smaller than the source size.
*/
static cell AMX_NATIVE_CALL n_urldecode(AMX *amx,const cell *params)
{
cell *cstr;
TCHAR *str;
int idx_src=0,idx_dst=0;
/* get the source */
(void)(amx);
amx_StrParam(amx,params[2],str);
/* decode */
while (idx_src!='\0') {
assert(idx_dst<=idx_src);
if (str[idx_src]=='%') {
int p,q;
if (str[idx_src+1]>='0' && str[idx_src+1]<='9')
p=str[idx_src+1]-'0';
else if (str[idx_src+1]>='A' && str[idx_src+1]<='F')
p=str[idx_src+1]-'A'+10;
else if (str[idx_src+1]>='a' && str[idx_src+1]<='f')
p=str[idx_src+1]-'a'+10;
else
p=-1;
if (p>=0) {
if (str[idx_src+2]>='0' && str[idx_src+2]<='9')
q=str[idx_src+2]-'0';
else if (str[idx_src+2]>='A' && str[idx_src+2]<='F')
q=str[idx_src+2]-'A'+10;
else if (str[idx_src+2]>='a' && str[idx_src+2]<='f')
q=str[idx_src+2]-'a'+10;
else
q=-1;
} /* if */
if (p>=0 && q >=0) {
assert(p<=15 && q<=15);
str[idx_dst]=(TCHAR)((p<<4) | q);
idx_src+=3;
} else {
/* invalid '%xx' syntax, copy literal '%' */
str[idx_dst]=str[idx_src++];
} /* if */
} else {
str[idx_dst]=str[idx_src++];
} /* if */
idx_dst++;
} /* while */
str[idx_dst]='\0';
/* store */
cstr=amx_Address(amx,params[1]);
amx_SetString(cstr,str,1,0,params[4]); /* store as packed ot unpacked */
return idx_dst;
}
#define INVALIDURI(c) ((c)<',' \
|| (c)>'9' && (c)<'A' \
|| (c)>'Z' && (c)<'_' \
|| (c)>'_' && (c)<'a' \
|| (c)>'z' && (unsigned)(c)<0xa1)
#define TOHEX(c) (TCHAR)((c)<10 ? '0'+(c) : 'A'-10+(c))
/* urlencode(dest[], const source[], maxlength=sizeof dest, bool:pack=false)
* Returns the number of characters encoded, excluding the zero string
* terminator; if the dest buffer is too small, not all bytes are stored.
* Always creates a packed string. This string has a newline character at the
* end. A buffer may be encoded "in-place" if the destination is large enough.
* Endian issues (for multi-byte values in the data stream) are not handled.
*/
static cell AMX_NATIVE_CALL n_urlencode(AMX *amx,const cell *params)
{
cell *cstr;
int length,destlen,count,lastwidth;
TCHAR *str;
/* allocate memory and get the source */
(void)(amx);
if ((length=(int)params[3])==0)
return 0;
if ((str = (TCHAR*)alloca(length * sizeof(TCHAR)))==NULL)
return 0;
cstr=amx_Address(amx,params[2]);
amx_GetString((char*)str, cstr, sizeof(TCHAR)>1, length);
/* run through the string and determine the new length */
destlen=1; /* space for the '\0' terminator */
lastwidth=0;
for (count=0; str[count]!='\0' && destlen<length; count++) {
if (INVALIDURI(str[count]))
lastwidth=3;
else
lastwidth=1;
destlen+=lastwidth;
} /* for */
if (destlen>length) { /* correct for overrun */
destlen-=lastwidth;
count--;
} /* if */
assert(destlen<=length);
assert(count>=0);
/* store string terminator */
assert(destlen>0);
str[--destlen]='\0';
/* convert string from end to start */
while (--count>=0) {
assert(destlen>count);
if (INVALIDURI(str[count])) {
str[--destlen]=TOHEX(str[count] & 0x0f);
str[--destlen]=TOHEX((str[count] >> 4) & 0x0f);
str[--destlen]='%';
} else {
str[--destlen]=str[count];
} /* if */
} /* while */
assert(destlen==0);
/* store the result */
cstr=amx_Address(amx,params[1]);
amx_SetString(cstr,str,1,0,params[4]); /* store as packed ot unpacked */
return (cell)strlen(str);
}
/* memcpy(dest[], const source[], index=0, numbytes, maxlength=sizeof dest)
* This function can align byte strings in cell arrays, or concatenate two
* byte strings in two arrays. The parameter "index" is a byte offset; "numbytes"
@ -928,11 +786,10 @@ static cell AMX_NATIVE_CALL n_memcpy(AMX *amx,const cell *params)
cell *cdest,*csrc;
unsigned char *pdest,*psrc;
(void)(amx);
if (params[3]<0 || params[4]<0 || (params[3]+params[4])>params[5]*(int)sizeof(cell))
return 0;
cdest=amx_Address(amx,params[1]);
csrc=amx_Address(amx,params[2]);
amx_GetAddr(amx,params[1],&cdest);
amx_GetAddr(amx,params[2],&csrc);
pdest=(unsigned char*)cdest+params[3];
psrc=(unsigned char*)csrc;
memmove(pdest,psrc,params[4]);
@ -949,7 +806,7 @@ static cell AMX_NATIVE_CALL n_memcpy(AMX *amx,const cell *params)
static int str_putchar(void *dest,TCHAR ch)
{
int len=(int)_tcslen((TCHAR*)dest);
int len=_tcslen((TCHAR*)dest);
if (len<MAX_FORMATSTR-1) {
((TCHAR*)dest)[len]=ch;
((TCHAR*)dest)[len+1]='\0';
@ -981,11 +838,11 @@ static cell AMX_NATIVE_CALL n_strformat(AMX *amx,const cell *params)
info.user=output;
output[0] = __T('\0');
cstr=amx_Address(amx,params[4]);
amx_GetAddr(amx,params[4],&cstr);
amx_printstring(amx,cstr,&info);
/* store the output string */
cstr=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&cstr);
amx_SetString(cstr,(char*)output,(int)params[3],sizeof(TCHAR)>1,(int)params[2]);
return 1;
#endif
@ -1000,7 +857,6 @@ const AMX_NATIVE_INFO string_Natives[] = {
{ "memcpy", n_memcpy },
{ "strcat", n_strcat },
{ "strcmp", n_strcmp },
{ "strcopy", n_strcopy },
{ "strdel", n_strdel },
{ "strfind", n_strfind },
{ "strformat", n_strformat },
@ -1012,18 +868,16 @@ const AMX_NATIVE_INFO string_Natives[] = {
{ "strval", n_strval },
{ "uudecode", n_uudecode },
{ "uuencode", n_uuencode },
{ "urldecode", n_urldecode },
{ "urlencode", n_urlencode },
{ "valstr", n_valstr },
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_StringInit(AMX *amx)
int AMXEXPORT amx_StringInit(AMX *amx)
{
return amx_Register(amx, string_Natives, -1);
}
int AMXEXPORT AMXAPI amx_StringCleanup(AMX *amx)
int AMXEXPORT amx_StringCleanup(AMX *amx)
{
(void)amx;
return AMX_ERR_NONE;

View File

@ -10,15 +10,15 @@
* All strings MUST have an explicit \0. See the Windows SDK documentation
* for details on version information and the VERSIONINFO structure.
*/
#define VERSION 4
#define REVISION 0
#define VERSION 1
#define REVISION 1
#define BUILD 0
#define VERSIONSTR "4.0.0\0"
#define VERSIONSTR "1.1.0\0"
#define VERSIONNAME "amxString.dll\0"
#define VERSIONDESCRIPTION "Pawn AMX: String manipulation routines\0"
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
#define VERSIONPRODUCTNAME "amxString\0"
#define VERSIONCOPYRIGHT "Copyright \251 2005-2016 ITB CompuPhase\0"
#define VERSIONCOPYRIGHT "Copyright \251 2005-2006 ITB CompuPhase\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION, REVISION, BUILD, 0

View File

@ -1,45 +1,36 @@
/* Date/time module for the Pawn Abstract Machine
*
* Copyright (c) ITB CompuPhase, 2001-2016
* Copyright (c) ITB CompuPhase, 2001-2006
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
* This software is provided "as-is", without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from
* the use of this software.
*
* http://www.apache.org/licenses/LICENSE-2.0
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*
* Version: $Id: amxtime.c 5588 2016-10-25 11:13:28Z $
* Version: $Id: amxtime.c 3649 2006-10-12 13:13:57Z thiadmer $
*/
#include <time.h>
#include <assert.h>
#include "amx.h"
#if defined __WIN32__ || defined _WIN32 || defined _Windows
#if defined __WIN32__ || defined _WIN32
#include <windows.h>
#include <mmsystem.h>
#endif
#if defined __GNUC__ || defined __clang__
#include <sys/time.h>
#endif
#if defined __clang__
/* ignore this warning, because fixing the macro would make it depend on
two's-complement arithmetic */
#pragma GCC diagnostic ignored "-Wshift-negative-value"
#endif
#define CELLMIN (-1 << (8*sizeof(cell) - 1))
#define SECONDS_PER_MINUTE 60
#define SECONDS_PER_HOUR 3600
#define SECONDS_PER_DAY 86400
#define SECONDS_PER_YEAR 31556952 /* based on 365.2425 days per year */
#if !defined CLOCKS_PER_SEC
#define CLOCKS_PER_SEC CLK_TCK
#endif
@ -75,168 +66,52 @@ static unsigned long gettimestamp(void)
#if defined __WIN32__ || defined _WIN32 || defined WIN32
value=timeGetTime(); /* this value is already in milliseconds */
#elif defined __linux || defined __linux__ || defined __LINUX__ || defined __APPLE__
struct timeval tv;
gettimeofday(&tv, NULL);
value = ((tv.tv_sec * 1000) + (tv.tv_usec / 1000));
#else
value=clock();
#if CLOCKS_PER_SEC<1000
value=(cell)clock();
#if CLOCKS_PER_SEC!=1000
/* convert to milliseconds */
value=(cell)((1000L * value) / CLOCKS_PER_SEC);
#elif CLOCKS_PER_SEC>1000
/* convert to milliseconds */
value=(cell)(value/(CLOCKS_PER_SEC/1000));
value=(cell)((1000L * (value+CLOCKS_PER_SEC/2)) / CLOCKS_PER_SEC);
#endif
#endif
return value;
}
void stamp2datetime(unsigned long sec1970,
int *year, int *month, int *day,
int *hour, int *minute, int *second)
{
int days, seconds;
/* find the year */
assert(year!=NULL);
for (*year = 1970; ; *year += 1) {
days = 365 + ((*year & 0x03) == 0); /* clumsy "leap-year" routine, fails for 2100 */
seconds = days * SECONDS_PER_DAY;
if ((unsigned long)seconds > sec1970)
break;
sec1970 -= seconds;
} /* if */
/* find the month */
assert(month!=NULL);
for (*month = 1; ; *month += 1) {
days = monthdays[*month - 1];
seconds = days * SECONDS_PER_DAY;
if ((unsigned long)seconds > sec1970)
break;
sec1970 -= seconds;
} /* if */
/* find the day */
assert(day!=NULL);
for (*day = 1; sec1970 >= SECONDS_PER_DAY; *day += 1)
sec1970 -= SECONDS_PER_DAY;
/* find the hour */
assert(hour!=NULL);
for (*hour = 0; sec1970 >= SECONDS_PER_HOUR; *hour += 1)
sec1970 -= SECONDS_PER_HOUR;
/* find the minute */
assert(minute!=NULL);
for (*minute = 0; sec1970 >= SECONDS_PER_MINUTE; *minute += 1)
sec1970 -= SECONDS_PER_MINUTE;
/* remainder is the number of seconds */
assert(second!=NULL);
*second = (int)sec1970;
}
static void settime(cell hour,cell minute,cell second)
{
#if defined __WIN32__ || defined _WIN32 || defined WIN32
SYSTEMTIME systim;
GetLocalTime(&systim);
if (hour!=CELLMIN)
systim.wHour=(WORD)wrap((int)hour,0,23);
if (minute!=CELLMIN)
systim.wMinute=(WORD)wrap((int)minute,0,59);
if (second!=CELLMIN)
systim.wSecond=(WORD)wrap((int)second,0,59);
SetLocalTime(&systim);
#else
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
* must have "root" permission to call stime(); many POSIX systems will
* have settimeofday() instead
*/
time_t sec1970;
struct tm gtm;
#if defined __APPLE__ /* also valid for other POSIX systems */
struct timeval tv;
#endif
time(&sec1970);
gtm=*localtime(&sec1970);
if (hour!=CELLMIN)
gtm.tm_hour=wrap((int)hour,0,23);
if (minute!=CELLMIN)
gtm.tm_min=wrap((int)minute,0,59);
if (second!=CELLMIN)
gtm.tm_sec=wrap((int)second,0,59);
sec1970=mktime(&gtm);
#if defined __APPLE__ /* also valid for other POSIX systems */
tv.tv_sec = sec1970;
tv.tv_usec = 0;
settimeofday(&tv, 0);
#else
stime(&sec1970);
#endif
#endif
}
static void setdate(cell year,cell month,cell day)
{
int maxday;
#if defined __WIN32__ || defined _WIN32 || defined WIN32
SYSTEMTIME systim;
GetLocalTime(&systim);
if (year!=CELLMIN)
systim.wYear=(WORD)wrap((int)year,1970,2099);
if (month!=CELLMIN)
systim.wMonth=(WORD)wrap((int)month,1,12);
maxday=monthdays[systim.wMonth - 1];
if (systim.wMonth==2 && ((systim.wYear % 4)==0 && ((systim.wYear % 100)!=0 || (systim.wYear % 400)==0)))
maxday++;
if (day!=CELLMIN)
systim.wDay=(WORD)wrap((int)day,1,maxday);
SetLocalTime(&systim);
#else
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
* must have "root" permission to call stime(); many POSIX systems will
* have settimeofday() instead
*/
time_t sec1970;
struct tm gtm;
#if defined __APPLE__ /* also valid for other POSIX systems */
struct timeval tv;
#endif
time(&sec1970);
gtm=*localtime(&sec1970);
if (year!=CELLMIN)
gtm.tm_year=year-1900;
if (month!=CELLMIN)
gtm.tm_mon=month-1;
if (day!=CELLMIN)
gtm.tm_mday=day;
sec1970=mktime(&gtm);
#if defined __APPLE__ /* also valid for other POSIX systems */
tv.tv_sec = sec1970;
tv.tv_usec = 0;
settimeofday(&tv, 0);
#else
stime(&sec1970);
#endif
#endif
}
/* settime(hour, minute, second)
* Always returns 0
*/
static cell AMX_NATIVE_CALL n_settime(AMX *amx, const cell *params)
{
#if defined __WIN32__ || defined _WIN32 || defined WIN32
SYSTEMTIME systim;
GetLocalTime(&systim);
if (params[1]!=CELLMIN)
systim.wHour=(WORD)wrap((int)params[1],0,23);
if (params[2]!=CELLMIN)
systim.wMinute=(WORD)wrap((int)params[2],0,59);
if (params[3]!=CELLMIN)
systim.wSecond=(WORD)wrap((int)params[3],0,59);
SetLocalTime(&systim);
#else
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
* must have "root" permission to call stime()
*/
time_t sec1970;
struct tm gtm;
(void)amx;
time(&sec1970);
gtm=*localtime(&sec1970);
if (params[1]!=CELLMIN)
gtm.tm_hour=wrap((int)params[1],0,23);
if (params[2]!=CELLMIN)
gtm.tm_min=wrap((int)params[2],0,59);
if (params[3]!=CELLMIN)
gtm.tm_sec=wrap((int)params[3],0,59);
sec1970=mktime(&gtm);
stime(&sec1970);
#endif
(void)amx;
settime(params[1],params[2],params[3]);
return 0;
}
@ -258,17 +133,17 @@ static cell AMX_NATIVE_CALL n_gettime(AMX *amx, const cell *params)
* library; in that case gmtime() and localtime() return the same value
*/
gtm=*localtime(&sec1970);
cptr=amx_Address(amx,params[1]);
*cptr=gtm.tm_hour;
cptr=amx_Address(amx,params[2]);
*cptr=gtm.tm_min;
cptr=amx_Address(amx,params[3]);
*cptr=gtm.tm_sec;
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
*cptr=gtm.tm_hour;
if (amx_GetAddr(amx,params[2],&cptr)==AMX_ERR_NONE)
*cptr=gtm.tm_min;
if (amx_GetAddr(amx,params[3],&cptr)==AMX_ERR_NONE)
*cptr=gtm.tm_sec;
/* the time() function returns the number of seconds since January 1 1970
* in Universal Coordinated Time (the successor to Greenwich Mean Time)
*/
return (cell)sec1970;
return sec1970;
}
/* setdate(year, month, day)
@ -276,8 +151,42 @@ static cell AMX_NATIVE_CALL n_gettime(AMX *amx, const cell *params)
*/
static cell AMX_NATIVE_CALL n_setdate(AMX *amx, const cell *params)
{
int maxday;
#if defined __WIN32__ || defined _WIN32 || defined WIN32
SYSTEMTIME systim;
GetLocalTime(&systim);
if (params[1]!=CELLMIN)
systim.wYear=(WORD)wrap((int)params[1],1970,2099);
if (params[2]!=CELLMIN)
systim.wMonth=(WORD)wrap((int)params[2],1,12);
maxday=monthdays[systim.wMonth - 1];
if (systim.wMonth==2 && ((systim.wYear % 4)==0 && ((systim.wYear % 100)!=0 || (systim.wYear % 400)==0)))
maxday++;
if (params[3]!=CELLMIN)
systim.wDay=(WORD)wrap((int)params[3],1,maxday);
SetLocalTime(&systim);
#else
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
* must have "root" permission to call stime()
*/
time_t sec1970;
struct tm gtm;
(void)amx;
time(&sec1970);
gtm=*localtime(&sec1970);
if (params[1]!=CELLMIN)
gtm.tm_year=params[1]-1900;
if (params[2]!=CELLMIN)
gtm.tm_mon=params[2]-1;
if (params[3]!=CELLMIN)
gtm.tm_mday=params[3];
sec1970=mktime(&gtm);
stime(&sec1970);
#endif
(void)amx;
setdate(params[1],params[2],params[3]);
return 0;
}
@ -296,12 +205,12 @@ static cell AMX_NATIVE_CALL n_getdate(AMX *amx, const cell *params)
time(&sec1970);
gtm=*localtime(&sec1970);
cptr=amx_Address(amx,params[1]);
*cptr=gtm.tm_year+1900;
cptr=amx_Address(amx,params[2]);
*cptr=gtm.tm_mon+1;
cptr=amx_Address(amx,params[3]);
*cptr=gtm.tm_mday;
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
*cptr=gtm.tm_year+1900;
if (amx_GetAddr(amx,params[2],&cptr)==AMX_ERR_NONE)
*cptr=gtm.tm_mon+1;
if (amx_GetAddr(amx,params[3],&cptr)==AMX_ERR_NONE)
*cptr=gtm.tm_mday;
return gtm.tm_yday+1;
}
@ -317,11 +226,12 @@ static cell AMX_NATIVE_CALL n_tickcount(AMX *amx, const cell *params)
assert(params[0]==(int)sizeof(cell));
INIT_TIMER();
cptr=amx_Address(amx,params[1]);
#if defined __WIN32__ || defined _WIN32 || defined WIN32
*cptr=1000; /* granularity = 1 ms */
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
*cptr=1000; /* granularity = 1 ms */
#else
*cptr=(cell)CLOCKS_PER_SEC; /* in Unix/Linux, this is often 100 */
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
*cptr=(cell)CLOCKS_PER_SEC; /* in Unix/Linux, this is often 100 */
#endif
return gettimestamp() & 0x7fffffff;
}
@ -366,59 +276,13 @@ static cell AMX_NATIVE_CALL n_gettimer(AMX *amx, const cell *params)
cell *cptr;
assert(params[0]==(int)(2*sizeof(cell)));
cptr=amx_Address(amx,params[1]);
*cptr=timelimit;
cptr=amx_Address(amx,params[2]);
*cptr=timerepeat;
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
*cptr=timelimit;
if (amx_GetAddr(amx,params[1],&cptr)==AMX_ERR_NONE)
*cptr=timerepeat;
return timelimit>0;
}
/* settimestamp(seconds1970) sets the date and time from a single parameter: the
* number of seconds since 1 January 1970.
*/
static cell AMX_NATIVE_CALL n_settimestamp(AMX *amx, const cell *params)
{
#if defined __WIN32__ || defined _WIN32 || defined WIN32
int year, month, day, hour, minute, second;
stamp2datetime(params[1],
&year, &month, &day,
&hour, &minute, &second);
setdate(year, month, day);
settime(hour, minute, second);
#else
/* Linux/Unix (and some DOS compilers) have stime(); on Linux/Unix, you
* must have "root" permission to call stime(); many POSIX systems will
* have settimeofday() instead
*/
#if defined __APPLE__ /* also valid for other POSIX systems */
struct timeval tv;
tv.tv_sec = params[1];
tv.tv_usec = 0;
settimeofday(&tv, 0);
#else
time_t sec1970=(time_t)params[1];
stime(&sec1970);
#endif
#endif
(void)amx;
return 0;
}
/* cvttimestamp(seconds1970, &year, &month, &day, &hour, &minute, &second)
*/
static cell AMX_NATIVE_CALL n_cvttimestamp(AMX *amx, const cell *params)
{
int year, month, day, hour, minute, second;
(void)amx;
stamp2datetime(params[1],
&year, &month, &day,
&hour, &minute, &second);
return 0;
}
#if !defined AMXTIME_NOIDLE
static AMX_IDLE PrevIdle = NULL;
@ -452,20 +316,18 @@ static int AMXAPI amx_TimeIdle(AMX *amx, int AMXAPI Exec(AMX *, cell *, int))
extern "C"
#endif
const AMX_NATIVE_INFO time_Natives[] = {
{ "gettime", n_gettime },
{ "settime", n_settime },
{ "getdate", n_getdate },
{ "setdate", n_setdate },
{ "tickcount", n_tickcount },
{ "settimer", n_settimer },
{ "gettimer", n_gettimer },
{ "delay", n_delay },
{ "settimestamp", n_settimestamp },
{ "cvttimestamp", n_cvttimestamp },
{ "gettime", n_gettime },
{ "settime", n_settime },
{ "getdate", n_getdate },
{ "setdate", n_setdate },
{ "tickcount", n_tickcount },
{ "settimer", n_settimer },
{ "gettimer", n_gettimer },
{ "delay", n_delay },
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_TimeInit(AMX *amx)
int AMXEXPORT amx_TimeInit(AMX *amx)
{
#if !defined AMXTIME_NOIDLE
/* see whether there is a @timer() function */
@ -479,7 +341,7 @@ int AMXEXPORT AMXAPI amx_TimeInit(AMX *amx)
return amx_Register(amx, time_Natives, -1);
}
int AMXEXPORT AMXAPI amx_TimeCleanup(AMX *amx)
int AMXEXPORT amx_TimeCleanup(AMX *amx)
{
(void)amx;
#if !defined AMXTIME_NOIDLE

View File

@ -10,15 +10,15 @@
* All strings MUST have an explicit \0. See the Windows SDK documentation
* for details on version information and the VERSIONINFO structure.
*/
#define VERSION 4
#define REVISION 0
#define VERSION 1
#define REVISION 1
#define BUILD 0
#define VERSIONSTR "4.0.0\0"
#define VERSIONSTR "1.2.0\0"
#define VERSIONNAME "amxTime.dll\0"
#define VERSIONDESCRIPTION "Pawn AMX: time routines\0"
#define VERSIONCOMPANYNAME "ITB CompuPhase\0"
#define VERSIONPRODUCTNAME "amxTime\0"
#define VERSIONCOPYRIGHT "Copyright \251 2005-2016 ITB CompuPhase\0"
#define VERSIONCOPYRIGHT "Copyright \251 2005-2006 ITB CompuPhase\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VERSION, REVISION, BUILD, 0

View File

@ -45,7 +45,7 @@ static cell AMX_NATIVE_CALL n_float(AMX *amx,const cell *params)
{
/*
* params[0] = number of bytes
* params[1] = integer value to convert to a float
* params[1] = long value to convert to a float
*/
REAL fValue;
@ -74,7 +74,7 @@ static cell AMX_NATIVE_CALL n_strfloat(AMX *amx,const cell *params)
assert(params[0]/sizeof(cell)==1);
/* Get the real address of the string. */
pString=amx_Address(amx,params[1]);
amx_GetAddr(amx,params[1],&pString);
/* Find out how long the string is in characters. */
amx_StrLen(pString, &nLen);
@ -163,20 +163,20 @@ static cell AMX_NATIVE_CALL n_floatround(AMX *amx,const cell *params)
/*
* params[0] = number of bytes
* params[1] = float operand
* params[2] = Type of rounding (integer)
* params[2] = Type of rounding (long)
*/
REAL fA = amx_ctof(params[1]);
(void)amx;
switch (params[2])
{
case 1: /* round downwards */
case 1: /* round downwards (truncate) */
fA = (REAL)(floor((double)fA));
break;
case 2: /* round upwards */
fA = (REAL)(ceil((double)fA));
break;
case 3: /* round towards zero (truncate) */
case 3: /* round towards zero */
if ( fA>=0.0 )
fA = (REAL)(floor((double)fA));
else
@ -187,7 +187,7 @@ static cell AMX_NATIVE_CALL n_floatround(AMX *amx,const cell *params)
break;
}
return (cell)fA;
return (long)fA;
}
/******************************************************************/
@ -284,7 +284,7 @@ static cell AMX_NATIVE_CALL n_floatsin(AMX *amx,const cell *params)
*/
REAL fA = amx_ctof(params[1]);
fA = ToRadians(fA, params[2]);
fA = (float)sin(fA);
fA = sin(fA);
(void)amx;
return amx_ftoc(fA);
}
@ -299,7 +299,7 @@ static cell AMX_NATIVE_CALL n_floatcos(AMX *amx,const cell *params)
*/
REAL fA = amx_ctof(params[1]);
fA = ToRadians(fA, params[2]);
fA = (float)cos(fA);
fA = cos(fA);
(void)amx;
return amx_ftoc(fA);
}
@ -314,7 +314,7 @@ static cell AMX_NATIVE_CALL n_floattan(AMX *amx,const cell *params)
*/
REAL fA = amx_ctof(params[1]);
fA = ToRadians(fA, params[2]);
fA = (float)tan(fA);
fA = tan(fA);
(void)amx;
return amx_ftoc(fA);
}
@ -328,22 +328,6 @@ static cell AMX_NATIVE_CALL n_floatabs(AMX *amx,const cell *params)
return amx_ftoc(fA);
}
/******************************************************************/
/* return the integer part of a real value, truncated
* Return integer part of float, truncated (same as floatround
* with mode 3)
*/
static cell AMX_NATIVE_CALL n_floatint(AMX *amx,const cell *params)
{
REAL fA = amx_ctof(params[1]);
if ( fA>=0.0 )
fA = (REAL)(floor((double)fA));
else
fA = (REAL)(ceil((double)fA));
(void)amx;
return (cell)fA;
}
#if defined __cplusplus
extern "C"
#endif
@ -364,16 +348,15 @@ const AMX_NATIVE_INFO float_Natives[] = {
{ "floatcos", n_floatcos },
{ "floattan", n_floattan },
{ "floatabs", n_floatabs },
{ "floatint", n_floatint }, // also add user-defined operator "="
{ NULL, NULL } /* terminator */
};
int AMXEXPORT AMXAPI amx_FloatInit(AMX *amx)
int AMXEXPORT amx_FloatInit(AMX *amx)
{
return amx_Register(amx,float_Natives,-1);
}
int AMXEXPORT AMXAPI amx_FloatCleanup(AMX *amx)
int AMXEXPORT amx_FloatCleanup(AMX *amx)
{
(void)amx;
return AMX_ERR_NONE;

View File

@ -1,31 +0,0 @@
/* Glue functions for the minIni library, based on the C/C++ stdio library
*
* Or better said: this file contains macros that maps the function interface
* used by minIni to the standard C/C++ file I/O functions.
*
* By CompuPhase, 2008-2014
* This "glue file" is in the public domain. It is distributed without
* warranties or conditions of any kind, either express or implied.
*/
/* map required file I/O types and functions to the standard C library */
#include <stdio.h>
#define INI_FILETYPE FILE*
#define ini_openread(filename,file) ((*(file) = fopen((filename),"rb")) != NULL)
#define ini_openwrite(filename,file) ((*(file) = fopen((filename),"wb")) != NULL)
#define ini_openrewrite(filename,file) ((*(file) = fopen((filename),"r+b")) != NULL)
#define ini_close(file) (fclose(*(file)) == 0)
#define ini_read(buffer,size,file) (fgets((buffer),(size),*(file)) != NULL)
#define ini_write(buffer,file) (fputs((buffer),*(file)) >= 0)
#define ini_rename(source,dest) (rename((source), (dest)) == 0)
#define ini_remove(filename) (remove(filename) == 0)
#define INI_FILEPOS long int
#define ini_tell(file,pos) (*(pos) = ftell(*(file)))
#define ini_seek(file,pos) (fseek(*(file), *(pos), SEEK_SET) == 0)
/* for floating-point support, define additional types and functions */
#define INI_REAL float
#define ini_ftoa(string,value) sprintf((string),"%f",(value))
#define ini_atof(string) (INI_REAL)strtod((string),NULL)

View File

@ -1,878 +0,0 @@
/* minIni - Multi-Platform INI file parser, suitable for embedded systems
*
* These routines are in part based on the article "Multiplatform .INI Files"
* by Joseph J. Graf in the March 1994 issue of Dr. Dobb's Journal.
*
* Copyright (c) CompuPhase, 2008-2017
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: minIni.c 5690 2017-06-08 14:04:08Z thiadmer $
*/
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
# if !defined UNICODE /* for Windows */
# define UNICODE
# endif
# if !defined _UNICODE /* for C library */
# define _UNICODE
# endif
#endif
#define MININI_IMPLEMENTATION
#include "minIni.h"
#if defined NDEBUG
#if defined assert
#undef assert
#endif
#define assert(e)
#else
#include <assert.h>
#endif
#if !defined __T || defined INI_ANSIONLY
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#define TCHAR char
#define __T(s) s
#define _tcscat strcat
#define _tcschr strchr
#define _tcscmp strcmp
#define _tcscpy strcpy
#define _tcsicmp stricmp
#define _tcslen strlen
#define _tcsncmp strncmp
#define _tcsnicmp strnicmp
#define _tcsrchr strrchr
#define _tcstol strtol
#define _tcstod strtod
#define _totupper toupper
#define _stprintf sprintf
#define _tfgets fgets
#define _tfputs fputs
#define _tfopen fopen
#define _tremove remove
#define _trename rename
#endif
#if defined __linux || defined __linux__
#define __LINUX__
#elif defined FREEBSD && !defined __FreeBSD__
#define __FreeBSD__
#elif defined(_MSC_VER)
#pragma warning(disable: 4996) /* for Microsoft Visual C/C++ */
#endif
#if !defined strnicmp && !defined PORTABLE_STRNICMP
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
#define strnicmp strncasecmp
#endif
#endif
#if !defined _totupper
#include <ctype.h>
#define _totupper toupper
#endif
#if !defined INI_LINETERM
#if defined __LINUX__ || defined __FreeBSD__ || defined __OpenBSD__ || defined __APPLE__
#define INI_LINETERM __T("\n")
#else
#define INI_LINETERM __T("\r\n")
#endif
#endif
#if !defined INI_FILETYPE
#error Missing definition for INI_FILETYPE.
#endif
#if !defined sizearray
#define sizearray(a) (sizeof(a) / sizeof((a)[0]))
#endif
enum quote_option {
QUOTE_NONE,
QUOTE_ENQUOTE,
QUOTE_DEQUOTE,
};
#if defined PORTABLE_STRNICMP
int strnicmp(const TCHAR *s1, const TCHAR *s2, size_t n)
{
while (n-- != 0 && (*s1 || *s2)) {
register int c1, c2;
c1 = *s1++;
if ('a' <= c1 && c1 <= 'z')
c1 += ('A' - 'a');
c2 = *s2++;
if ('a' <= c2 && c2 <= 'z')
c2 += ('A' - 'a');
if (c1 != c2)
return c1 - c2;
} /* while */
return 0;
}
#endif /* PORTABLE_STRNICMP */
static TCHAR *skipleading(const TCHAR *str)
{
assert(str != NULL);
while ('\0' < *str && *str <= ' ')
str++;
return (TCHAR *)str;
}
static TCHAR *skiptrailing(const TCHAR *str, const TCHAR *base)
{
assert(str != NULL);
assert(base != NULL);
while (str > base && '\0' < *(str-1) && *(str-1) <= ' ')
str--;
return (TCHAR *)str;
}
static TCHAR *striptrailing(TCHAR *str)
{
TCHAR *ptr = skiptrailing(_tcschr(str, '\0'), str);
assert(ptr != NULL);
*ptr = '\0';
return str;
}
static TCHAR *save_strncpy(TCHAR *dest, const TCHAR *source, size_t maxlen, enum quote_option option)
{
size_t d, s;
assert(maxlen>0);
assert(dest <= source || dest >= source + maxlen);
if (option == QUOTE_ENQUOTE && maxlen < 3)
option = QUOTE_NONE; /* cannot store two quotes and a terminating zero in less than 3 characters */
switch (option) {
case QUOTE_NONE:
for (d = 0; d < maxlen - 1 && source[d] != '\0'; d++)
dest[d] = source[d];
assert(d < maxlen);
dest[d] = '\0';
break;
case QUOTE_ENQUOTE:
d = 0;
dest[d++] = '"';
for (s = 0; source[s] != '\0' && d < maxlen - 2; s++, d++) {
if (source[s] == '"') {
if (d >= maxlen - 3)
break; /* no space to store the escape character plus the one that follows it */
dest[d++] = '\\';
} /* if */
dest[d] = source[s];
} /* for */
dest[d++] = '"';
dest[d] = '\0';
break;
case QUOTE_DEQUOTE:
for (d = s = 0; source[s] != '\0' && d < maxlen - 1; s++, d++) {
if ((source[s] == '"' || source[s] == '\\') && source[s + 1] == '"')
s++;
dest[d] = source[s];
} /* for */
dest[d] = '\0';
break;
default:
assert(0);
} /* switch */
return dest;
}
static TCHAR *cleanstring(TCHAR *string, enum quote_option *quotes)
{
int isstring;
TCHAR *ep;
assert(string != NULL);
assert(quotes != NULL);
/* Remove a trailing comment */
isstring = 0;
for (ep = string; *ep != '\0' && ((*ep != ';' && *ep != '#') || isstring); ep++) {
if (*ep == '"') {
if (*(ep + 1) == '"')
ep++; /* skip "" (both quotes) */
else
isstring = !isstring; /* single quote, toggle isstring */
} else if (*ep == '\\' && *(ep + 1) == '"') {
ep++; /* skip \" (both quotes */
} /* if */
} /* for */
assert(ep != NULL && (*ep == '\0' || *ep == ';' || *ep == '#'));
*ep = '\0'; /* terminate at a comment */
striptrailing(string);
/* Remove double quotes surrounding a value */
*quotes = QUOTE_NONE;
if (*string == '"' && (ep = _tcschr(string, '\0')) != NULL && *(ep - 1) == '"') {
string++;
*--ep = '\0';
*quotes = QUOTE_DEQUOTE; /* this is a string, so remove escaped characters */
} /* if */
return string;
}
static int getkeystring(INI_FILETYPE *fp, const TCHAR *Section, const TCHAR *Key,
int idxSection, int idxKey, TCHAR *Buffer, int BufferSize,
INI_FILEPOS *mark)
{
TCHAR *sp, *ep;
int len, idx;
enum quote_option quotes;
TCHAR LocalBuffer[INI_BUFFERSIZE];
assert(fp != NULL);
/* Move through file 1 line at a time until a section is matched or EOF. If
* parameter Section is NULL, only look at keys above the first section. If
* idxSection is postive, copy the relevant section name.
*/
len = (Section != NULL) ? (int)_tcslen(Section) : 0;
if (len > 0 || idxSection >= 0) {
assert(Section != NULL);
idx = -1;
do {
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, fp))
return 0;
sp = skipleading(LocalBuffer);
ep = _tcsrchr(sp, ']');
} while (*sp != '[' || ep == NULL || (((int)(ep-sp-1) != len || _tcsnicmp(sp+1,Section,len) != 0) && ++idx != idxSection));
if (idxSection >= 0) {
if (idx == idxSection) {
assert(ep != NULL);
assert(*ep == ']');
*ep = '\0';
save_strncpy(Buffer, sp + 1, BufferSize, QUOTE_NONE);
return 1;
} /* if */
return 0; /* no more section found */
} /* if */
} /* if */
/* Now that the section has been found, find the entry.
* Stop searching upon leaving the section's area.
*/
assert(Key != NULL || idxKey >= 0);
len = (Key != NULL) ? (int)_tcslen(Key) : 0;
idx = -1;
do {
if (mark != NULL)
ini_tell(fp, mark); /* optionally keep the mark to the start of the line */
if (!ini_read(LocalBuffer,INI_BUFFERSIZE,fp) || *(sp = skipleading(LocalBuffer)) == '[')
return 0;
sp = skipleading(LocalBuffer);
ep = _tcschr(sp, '='); /* Parse out the equal sign */
if (ep == NULL)
ep = _tcschr(sp, ':');
} while (*sp == ';' || *sp == '#' || ep == NULL
|| ((len == 0 || (int)(skiptrailing(ep,sp)-sp) != len || _tcsnicmp(sp,Key,len) != 0) && ++idx != idxKey));
if (idxKey >= 0) {
if (idx == idxKey) {
assert(ep != NULL);
assert(*ep == '=' || *ep == ':');
*ep = '\0';
striptrailing(sp);
save_strncpy(Buffer, sp, BufferSize, QUOTE_NONE);
return 1;
} /* if */
return 0; /* no more key found (in this section) */
} /* if */
/* Copy up to BufferSize chars to buffer */
assert(ep != NULL);
assert(*ep == '=' || *ep == ':');
sp = skipleading(ep + 1);
sp = cleanstring(sp, &quotes); /* Remove a trailing comment */
save_strncpy(Buffer, sp, BufferSize, quotes);
return 1;
}
/** ini_gets()
* \param Section the name of the section to search for
* \param Key the name of the entry to find the value of
* \param DefValue default string in the event of a failed read
* \param Buffer a pointer to the buffer to copy into
* \param BufferSize the maximum number of characters to copy
* \param Filename the name and full path of the .ini file to read from
*
* \return the number of characters copied into the supplied buffer
*/
int ini_gets(const TCHAR *Section, const TCHAR *Key, const TCHAR *DefValue,
TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
{
INI_FILETYPE fp;
int ok = 0;
if (Buffer == NULL || BufferSize <= 0 || Key == NULL)
return 0;
if (ini_openread(Filename, &fp)) {
ok = getkeystring(&fp, Section, Key, -1, -1, Buffer, BufferSize, NULL);
(void)ini_close(&fp);
} /* if */
if (!ok)
save_strncpy(Buffer, (DefValue != NULL) ? DefValue : __T(""), BufferSize, QUOTE_NONE);
return (int)_tcslen(Buffer);
}
/** ini_getl()
* \param Section the name of the section to search for
* \param Key the name of the entry to find the value of
* \param DefValue the default value in the event of a failed read
* \param Filename the name of the .ini file to read from
*
* \return the value located at Key
*/
long ini_getl(const TCHAR *Section, const TCHAR *Key, long DefValue, const TCHAR *Filename)
{
TCHAR LocalBuffer[64];
int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
return (len == 0) ? DefValue
: ((len >= 2 && _totupper((int)LocalBuffer[1]) == 'X') ? _tcstol(LocalBuffer, NULL, 16)
: _tcstol(LocalBuffer, NULL, 10));
}
#if defined INI_REAL
/** ini_getf()
* \param Section the name of the section to search for
* \param Key the name of the entry to find the value of
* \param DefValue the default value in the event of a failed read
* \param Filename the name of the .ini file to read from
*
* \return the value located at Key
*/
INI_REAL ini_getf(const TCHAR *Section, const TCHAR *Key, INI_REAL DefValue, const TCHAR *Filename)
{
TCHAR LocalBuffer[64];
int len = ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
return (len == 0) ? DefValue : ini_atof(LocalBuffer);
}
#endif
/** ini_getbool()
* \param Section the name of the section to search for
* \param Key the name of the entry to find the value of
* \param DefValue default value in the event of a failed read; it should
* zero (0) or one (1).
* \param Filename the name and full path of the .ini file to read from
*
* A true boolean is found if one of the following is matched:
* - A string starting with 'y' or 'Y'
* - A string starting with 't' or 'T'
* - A string starting with '1'
*
* A false boolean is found if one of the following is matched:
* - A string starting with 'n' or 'N'
* - A string starting with 'f' or 'F'
* - A string starting with '0'
*
* \return the true/false flag as interpreted at Key
*/
int ini_getbool(const TCHAR *Section, const TCHAR *Key, int DefValue, const TCHAR *Filename)
{
TCHAR LocalBuffer[2] = __T("");
int ret;
ini_gets(Section, Key, __T(""), LocalBuffer, sizearray(LocalBuffer), Filename);
LocalBuffer[0] = (TCHAR)_totupper((int)LocalBuffer[0]);
if (LocalBuffer[0] == 'Y' || LocalBuffer[0] == '1' || LocalBuffer[0] == 'T')
ret = 1;
else if (LocalBuffer[0] == 'N' || LocalBuffer[0] == '0' || LocalBuffer[0] == 'F')
ret = 0;
else
ret = DefValue;
return(ret);
}
/** ini_getsection()
* \param idx the zero-based sequence number of the section to return
* \param Buffer a pointer to the buffer to copy into
* \param BufferSize the maximum number of characters to copy
* \param Filename the name and full path of the .ini file to read from
*
* \return the number of characters copied into the supplied buffer
*/
int ini_getsection(int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
{
INI_FILETYPE fp;
int ok = 0;
if (Buffer == NULL || BufferSize <= 0 || idx < 0)
return 0;
if (ini_openread(Filename, &fp)) {
ok = getkeystring(&fp, NULL, NULL, idx, -1, Buffer, BufferSize, NULL);
(void)ini_close(&fp);
} /* if */
if (!ok)
*Buffer = '\0';
return (int)_tcslen(Buffer);
}
/** ini_getkey()
* \param Section the name of the section to browse through, or NULL to
* browse through the keys outside any section
* \param idx the zero-based sequence number of the key to return
* \param Buffer a pointer to the buffer to copy into
* \param BufferSize the maximum number of characters to copy
* \param Filename the name and full path of the .ini file to read from
*
* \return the number of characters copied into the supplied buffer
*/
int ini_getkey(const TCHAR *Section, int idx, TCHAR *Buffer, int BufferSize, const TCHAR *Filename)
{
INI_FILETYPE fp;
int ok = 0;
if (Buffer == NULL || BufferSize <= 0 || idx < 0)
return 0;
if (ini_openread(Filename, &fp)) {
ok = getkeystring(&fp, Section, NULL, -1, idx, Buffer, BufferSize, NULL);
(void)ini_close(&fp);
} /* if */
if (!ok)
*Buffer = '\0';
return (int)_tcslen(Buffer);
}
#if !defined INI_NOBROWSE
/** ini_browse()
* \param Callback a pointer to a function that will be called for every
* setting in the INI file.
* \param UserData arbitrary data, which the function passes on the the
* \c Callback function
* \param Filename the name and full path of the .ini file to read from
*
* \return 1 on success, 0 on failure (INI file not found)
*
* \note The \c Callback function must return 1 to continue
* browsing through the INI file, or 0 to stop. Even when the
* callback stops the browsing, this function will return 1
* (for success).
*/
int ini_browse(INI_CALLBACK Callback, const void *UserData, const TCHAR *Filename)
{
TCHAR LocalBuffer[INI_BUFFERSIZE];
int lenSec, lenKey;
enum quote_option quotes;
INI_FILETYPE fp;
if (Callback == NULL)
return 0;
if (!ini_openread(Filename, &fp))
return 0;
LocalBuffer[0] = '\0'; /* copy an empty section in the buffer */
lenSec = (int)_tcslen(LocalBuffer) + 1;
for ( ;; ) {
TCHAR *sp, *ep;
if (!ini_read(LocalBuffer + lenSec, INI_BUFFERSIZE - lenSec, &fp))
break;
sp = skipleading(LocalBuffer + lenSec);
/* ignore empty strings and comments */
if (*sp == '\0' || *sp == ';' || *sp == '#')
continue;
/* see whether we reached a new section */
ep = _tcsrchr(sp, ']');
if (*sp == '[' && ep != NULL) {
*ep = '\0';
save_strncpy(LocalBuffer, sp + 1, INI_BUFFERSIZE, QUOTE_NONE);
lenSec = (int)_tcslen(LocalBuffer) + 1;
continue;
} /* if */
/* not a new section, test for a key/value pair */
ep = _tcschr(sp, '='); /* test for the equal sign or colon */
if (ep == NULL)
ep = _tcschr(sp, ':');
if (ep == NULL)
continue; /* invalid line, ignore */
*ep++ = '\0'; /* split the key from the value */
striptrailing(sp);
save_strncpy(LocalBuffer + lenSec, sp, INI_BUFFERSIZE - lenSec, QUOTE_NONE);
lenKey = (int)_tcslen(LocalBuffer + lenSec) + 1;
/* clean up the value */
sp = skipleading(ep);
sp = cleanstring(sp, &quotes); /* Remove a trailing comment */
save_strncpy(LocalBuffer + lenSec + lenKey, sp, INI_BUFFERSIZE - lenSec - lenKey, quotes);
/* call the callback */
if (!Callback(LocalBuffer, LocalBuffer + lenSec, LocalBuffer + lenSec + lenKey, UserData))
break;
} /* for */
(void)ini_close(&fp);
return 1;
}
#endif /* INI_NOBROWSE */
#if ! defined INI_READONLY
static void ini_tempname(TCHAR *dest, const TCHAR *source, int maxlength)
{
TCHAR *p;
save_strncpy(dest, source, maxlength, QUOTE_NONE);
p = _tcsrchr(dest, '\0');
assert(p != NULL);
*(p - 1) = '~';
}
static enum quote_option check_enquote(const TCHAR *Value)
{
const TCHAR *p;
/* run through the value, if it has trailing spaces, or '"', ';' or '#'
* characters, enquote it
*/
assert(Value != NULL);
for (p = Value; *p != '\0' && *p != '"' && *p != ';' && *p != '#'; p++)
/* nothing */;
return (*p != '\0' || (p > Value && *(p - 1) == ' ')) ? QUOTE_ENQUOTE : QUOTE_NONE;
}
static void writesection(TCHAR *LocalBuffer, const TCHAR *Section, INI_FILETYPE *fp)
{
if (Section != NULL && _tcslen(Section) > 0) {
TCHAR *p;
LocalBuffer[0] = '[';
save_strncpy(LocalBuffer + 1, Section, INI_BUFFERSIZE - 4, QUOTE_NONE); /* -1 for '[', -1 for ']', -2 for '\r\n' */
p = _tcsrchr(LocalBuffer, '\0');
assert(p != NULL);
*p++ = ']';
_tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */
if (fp != NULL)
(void)ini_write(LocalBuffer, fp);
} /* if */
}
static void writekey(TCHAR *LocalBuffer, const TCHAR *Key, const TCHAR *Value, INI_FILETYPE *fp)
{
TCHAR *p;
enum quote_option option = check_enquote(Value);
save_strncpy(LocalBuffer, Key, INI_BUFFERSIZE - 3, QUOTE_NONE); /* -1 for '=', -2 for '\r\n' */
p = _tcsrchr(LocalBuffer, '\0');
assert(p != NULL);
*p++ = '=';
save_strncpy(p, Value, INI_BUFFERSIZE - (p - LocalBuffer) - 2, option); /* -2 for '\r\n' */
p = _tcsrchr(LocalBuffer, '\0');
assert(p != NULL);
_tcscpy(p, INI_LINETERM); /* copy line terminator (typically "\n") */
if (fp != NULL)
(void)ini_write(LocalBuffer, fp);
}
static int cache_accum(const TCHAR *string, int *size, int max)
{
int len = (int)_tcslen(string);
if (*size + len >= max)
return 0;
*size += len;
return 1;
}
static int cache_flush(TCHAR *buffer, int *size,
INI_FILETYPE *rfp, INI_FILETYPE *wfp, INI_FILEPOS *mark)
{
int terminator_len = (int)_tcslen(INI_LINETERM);
int pos = 0;
(void)ini_seek(rfp, mark);
assert(buffer != NULL);
buffer[0] = '\0';
assert(size != NULL);
assert(*size <= INI_BUFFERSIZE);
while (pos < *size) {
(void)ini_read(buffer + pos, INI_BUFFERSIZE - pos, rfp);
while (pos < *size && buffer[pos] != '\0')
pos++; /* cannot use _tcslen() because buffer may not be zero-terminated */
} /* while */
if (buffer[0] != '\0') {
assert(pos > 0 && pos <= INI_BUFFERSIZE);
if (pos == INI_BUFFERSIZE)
pos--;
buffer[pos] = '\0'; /* force zero-termination (may be left unterminated in the above while loop) */
(void)ini_write(buffer, wfp);
}
ini_tell(rfp, mark); /* update mark */
*size = 0;
/* return whether the buffer ended with a line termination */
return (pos > terminator_len) && (_tcscmp(buffer + pos - terminator_len, INI_LINETERM) == 0);
}
static int close_rename(INI_FILETYPE *rfp, INI_FILETYPE *wfp, const TCHAR *filename, TCHAR *buffer)
{
(void)ini_close(rfp);
(void)ini_close(wfp);
(void)ini_remove(filename);
(void)ini_tempname(buffer, filename, INI_BUFFERSIZE);
(void)ini_rename(buffer, filename);
return 1;
}
/** ini_puts()
* \param Section the name of the section to write the string in
* \param Key the name of the entry to write, or NULL to erase all keys in the section
* \param Value a pointer to the buffer the string, or NULL to erase the key
* \param Filename the name and full path of the .ini file to write to
*
* \return 1 if successful, otherwise 0
*/
int ini_puts(const TCHAR *Section, const TCHAR *Key, const TCHAR *Value, const TCHAR *Filename)
{
INI_FILETYPE rfp;
INI_FILETYPE wfp;
INI_FILEPOS mark;
INI_FILEPOS head, tail;
TCHAR *sp, *ep;
TCHAR LocalBuffer[INI_BUFFERSIZE];
int len, match, flag, cachelen;
assert(Filename != NULL);
if (!ini_openread(Filename, &rfp)) {
/* If the .ini file doesn't exist, make a new file */
if (Key != NULL && Value != NULL) {
if (!ini_openwrite(Filename, &wfp))
return 0;
writesection(LocalBuffer, Section, &wfp);
writekey(LocalBuffer, Key, Value, &wfp);
(void)ini_close(&wfp);
} /* if */
return 1;
} /* if */
/* If parameters Key and Value are valid (so this is not an "erase" request)
* and the setting already exists, there are two short-cuts to avoid rewriting
* the INI file.
*/
if (Key != NULL && Value != NULL) {
ini_tell(&rfp, &mark);
match = getkeystring(&rfp, Section, Key, -1, -1, LocalBuffer, sizearray(LocalBuffer), &head);
if (match) {
/* if the current setting is identical to the one to write, there is
* nothing to do.
*/
if (_tcscmp(LocalBuffer,Value) == 0) {
(void)ini_close(&rfp);
return 1;
} /* if */
/* if the new setting has the same length as the current setting, and the
* glue file permits file read/write access, we can modify in place.
*/
#if defined ini_openrewrite
/* we already have the start of the (raw) line, get the end too */
ini_tell(&rfp, &tail);
/* create new buffer (without writing it to file) */
writekey(LocalBuffer, Key, Value, NULL);
if (_tcslen(LocalBuffer) == (size_t)(tail - head)) {
/* length matches, close the file & re-open for read/write, then
* write at the correct position
*/
(void)ini_close(&rfp);
if (!ini_openrewrite(Filename, &wfp))
return 0;
(void)ini_seek(&wfp, &head);
(void)ini_write(LocalBuffer, &wfp);
(void)ini_close(&wfp);
return 1;
} /* if */
#endif
} /* if */
/* key not found, or different value & length -> proceed (but rewind the
* input file first)
*/
(void)ini_seek(&rfp, &mark);
} /* if */
/* Get a temporary file name to copy to. Use the existing name, but with
* the last character set to a '~'.
*/
ini_tempname(LocalBuffer, Filename, INI_BUFFERSIZE);
if (!ini_openwrite(LocalBuffer, &wfp)) {
(void)ini_close(&rfp);
return 0;
} /* if */
(void)ini_tell(&rfp, &mark);
cachelen = 0;
/* Move through the file one line at a time until a section is
* matched or until EOF. Copy to temp file as it is read.
*/
len = (Section != NULL) ? (int)_tcslen(Section) : 0;
if (len > 0) {
do {
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
/* Failed to find section, so add one to the end */
flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
if (Key!=NULL && Value!=NULL) {
if (!flag)
(void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */
writesection(LocalBuffer, Section, &wfp);
writekey(LocalBuffer, Key, Value, &wfp);
} /* if */
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
} /* if */
/* Copy the line from source to dest, but not if this is the section that
* we are looking for and this section must be removed
*/
sp = skipleading(LocalBuffer);
ep = _tcsrchr(sp, ']');
match = (*sp == '[' && ep != NULL && (int)(ep-sp-1) == len && _tcsnicmp(sp + 1,Section,len) == 0);
if (!match || Key != NULL) {
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
} /* if */
} /* if */
} while (!match);
} /* if */
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
/* when deleting a section, the section head that was just found has not been
* copied to the output file, but because this line was not "accumulated" in
* the cache, the position in the input file was reset to the point just
* before the section; this must now be skipped (again)
*/
if (Key == NULL) {
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
(void)ini_tell(&rfp, &mark);
} /* if */
/* Now that the section has been found, find the entry. Stop searching
* upon leaving the section's area. Copy the file as it is read
* and create an entry if one is not found.
*/
len = (Key != NULL) ? (int)_tcslen(Key) : 0;
for( ;; ) {
if (!ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
/* EOF without an entry so make one */
flag = cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
if (Key!=NULL && Value!=NULL) {
if (!flag)
(void)ini_write(INI_LINETERM, &wfp); /* force a new line behind the last line of the INI file */
writekey(LocalBuffer, Key, Value, &wfp);
} /* if */
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
} /* if */
sp = skipleading(LocalBuffer);
ep = _tcschr(sp, '='); /* Parse out the equal sign */
if (ep == NULL)
ep = _tcschr(sp, ':');
match = (ep != NULL && len > 0 && (int)(skiptrailing(ep,sp)-sp) == len && _tcsnicmp(sp,Key,len) == 0);
if ((Key != NULL && match) || *sp == '[')
break; /* found the key, or found a new section */
/* copy other keys in the section */
if (Key == NULL) {
(void)ini_tell(&rfp, &mark); /* we are deleting the entire section, so update the read position */
} else {
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
} /* if */
} /* if */
} /* for */
/* the key was found, or we just dropped on the next section (meaning that it
* wasn't found); in both cases we need to write the key, but in the latter
* case, we also need to write the line starting the new section after writing
* the key
*/
flag = (*sp == '[');
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
if (Key != NULL && Value != NULL)
writekey(LocalBuffer, Key, Value, &wfp);
/* cache_flush() reset the "read pointer" to the start of the line with the
* previous key or the new section; read it again (because writekey() destroyed
* the buffer)
*/
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
if (flag) {
/* the new section heading needs to be copied to the output file */
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
} else {
/* forget the old key line */
(void)ini_tell(&rfp, &mark);
} /* if */
/* Copy the rest of the INI file */
while (ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp)) {
if (!cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE)) {
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
(void)ini_read(LocalBuffer, INI_BUFFERSIZE, &rfp);
cache_accum(LocalBuffer, &cachelen, INI_BUFFERSIZE);
} /* if */
} /* while */
cache_flush(LocalBuffer, &cachelen, &rfp, &wfp, &mark);
return close_rename(&rfp, &wfp, Filename, LocalBuffer); /* clean up and rename */
}
/* Ansi C "itoa" based on Kernighan & Ritchie's "Ansi C" book. */
#define ABS(v) ((v) < 0 ? -(v) : (v))
static void strreverse(TCHAR *str)
{
int i, j;
for (i = 0, j = (int)_tcslen(str) - 1; i < j; i++, j--) {
TCHAR t = str[i];
str[i] = str[j];
str[j] = t;
} /* for */
}
static void long2str(long value, TCHAR *str)
{
int i = 0;
long sign = value;
/* generate digits in reverse order */
do {
int n = (int)(value % 10); /* get next lowest digit */
str[i++] = (TCHAR)(ABS(n) + '0'); /* handle case of negative digit */
} while (value /= 10); /* delete the lowest digit */
if (sign < 0)
str[i++] = '-';
str[i] = '\0';
strreverse(str);
}
/** ini_putl()
* \param Section the name of the section to write the value in
* \param Key the name of the entry to write
* \param Value the value to write
* \param Filename the name and full path of the .ini file to write to
*
* \return 1 if successful, otherwise 0
*/
int ini_putl(const TCHAR *Section, const TCHAR *Key, long Value, const TCHAR *Filename)
{
TCHAR LocalBuffer[32];
long2str(Value, LocalBuffer);
return ini_puts(Section, Key, LocalBuffer, Filename);
}
#if defined INI_REAL
/** ini_putf()
* \param Section the name of the section to write the value in
* \param Key the name of the entry to write
* \param Value the value to write
* \param Filename the name and full path of the .ini file to write to
*
* \return 1 if successful, otherwise 0
*/
int ini_putf(const TCHAR *Section, const TCHAR *Key, INI_REAL Value, const TCHAR *Filename)
{
TCHAR LocalBuffer[64];
ini_ftoa(LocalBuffer, Value);
return ini_puts(Section, Key, LocalBuffer, Filename);
}
#endif /* INI_REAL */
#endif /* !INI_READONLY */

View File

@ -1,152 +0,0 @@
/* minIni - Multi-Platform INI file parser, suitable for embedded systems
*
* Copyright (c) CompuPhase, 2008-2012
*
* Licensed under the Apache License, Version 2.0 (the "License"); you may not
* use this file except in compliance with the License. You may obtain a copy
* of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*
* Version: $Id: minIni.h 5181 2015-01-21 09:44:28Z thiadmer $
*/
#ifndef MININI_H
#define MININI_H
#include "minGlue.h"
#if (defined _UNICODE || defined __UNICODE__ || defined UNICODE) && !defined INI_ANSIONLY
#include <tchar.h>
#define mTCHAR TCHAR
#else
/* force TCHAR to be "char", but only for minIni */
#define mTCHAR char
#endif
#if !defined INI_BUFFERSIZE
#define INI_BUFFERSIZE 512
#endif
#if defined __cplusplus
extern "C" {
#endif
int ini_getbool(const mTCHAR *Section, const mTCHAR *Key, int DefValue, const mTCHAR *Filename);
long ini_getl(const mTCHAR *Section, const mTCHAR *Key, long DefValue, const mTCHAR *Filename);
int ini_gets(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *DefValue, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int ini_getsection(int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
int ini_getkey(const mTCHAR *Section, int idx, mTCHAR *Buffer, int BufferSize, const mTCHAR *Filename);
#if defined INI_REAL
INI_REAL ini_getf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL DefValue, const mTCHAR *Filename);
#endif
#if !defined INI_READONLY
int ini_putl(const mTCHAR *Section, const mTCHAR *Key, long Value, const mTCHAR *Filename);
int ini_puts(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const mTCHAR *Filename);
#if defined INI_REAL
int ini_putf(const mTCHAR *Section, const mTCHAR *Key, INI_REAL Value, const mTCHAR *Filename);
#endif
#endif /* INI_READONLY */
#if !defined INI_NOBROWSE
typedef int (*INI_CALLBACK)(const mTCHAR *Section, const mTCHAR *Key, const mTCHAR *Value, const void *UserData);
int ini_browse(INI_CALLBACK Callback, const void *UserData, const mTCHAR *Filename);
#endif /* INI_NOBROWSE */
#if defined __cplusplus
}
#endif
#if defined __cplusplus
#if defined __WXWINDOWS__
#include "wxMinIni.h"
#else
#include <string>
/* The C++ class in minIni.h was contributed by Steven Van Ingelgem. */
class minIni
{
public:
minIni(const std::string& filename) : iniFilename(filename)
{ }
bool getbool(const std::string& Section, const std::string& Key, bool DefValue=false) const
{ return ini_getbool(Section.c_str(), Key.c_str(), int(DefValue), iniFilename.c_str()) != 0; }
long getl(const std::string& Section, const std::string& Key, long DefValue=0) const
{ return ini_getl(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
int geti(const std::string& Section, const std::string& Key, int DefValue=0) const
{ return static_cast<int>(this->getl(Section, Key, long(DefValue))); }
std::string gets(const std::string& Section, const std::string& Key, const std::string& DefValue="") const
{
char buffer[INI_BUFFERSIZE];
ini_gets(Section.c_str(), Key.c_str(), DefValue.c_str(), buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
std::string getsection(int idx) const
{
char buffer[INI_BUFFERSIZE];
ini_getsection(idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
std::string getkey(const std::string& Section, int idx) const
{
char buffer[INI_BUFFERSIZE];
ini_getkey(Section.c_str(), idx, buffer, INI_BUFFERSIZE, iniFilename.c_str());
return buffer;
}
#if defined INI_REAL
INI_REAL getf(const std::string& Section, const std::string& Key, INI_REAL DefValue=0) const
{ return ini_getf(Section.c_str(), Key.c_str(), DefValue, iniFilename.c_str()); }
#endif
#if ! defined INI_READONLY
bool put(const std::string& Section, const std::string& Key, long Value) const
{ return ini_putl(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, int Value) const
{ return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, bool Value) const
{ return ini_putl(Section.c_str(), Key.c_str(), (long)Value, iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, const std::string& Value) const
{ return ini_puts(Section.c_str(), Key.c_str(), Value.c_str(), iniFilename.c_str()) != 0; }
bool put(const std::string& Section, const std::string& Key, const char* Value) const
{ return ini_puts(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
#if defined INI_REAL
bool put(const std::string& Section, const std::string& Key, INI_REAL Value) const
{ return ini_putf(Section.c_str(), Key.c_str(), Value, iniFilename.c_str()) != 0; }
#endif
bool del(const std::string& Section, const std::string& Key) const
{ return ini_puts(Section.c_str(), Key.c_str(), 0, iniFilename.c_str()) != 0; }
bool del(const std::string& Section) const
{ return ini_puts(Section.c_str(), 0, 0, iniFilename.c_str()) != 0; }
#endif
private:
std::string iniFilename;
};
#endif /* __WXWINDOWS__ */
#endif /* __cplusplus */
#endif /* MININI_H */