Quantcast
Channel: SA-MP Forums
Viewing all articles
Browse latest Browse all 18226

Help YSI 4.0

$
0
0
I have updated ysi 4.0 but have 2 include my error I want to fix it
Code:

C:\Users\Administrator\Desktop\GTA-RP.VN\Windowns2k8\Windowns2k8\pawno\include\strlib.inc(1641) : error 021: symbol already defined: "sprintf"
C:\Users\Administrator\Desktop\GTA-RP.VN\Windowns2k8\Windowns2k8\pawno\include\fuckcleo.inc(55) : warning 219: local variable "using_deprecated_foreach_syntax" shadows a variable at a preceding level
C:\Users\Administrator\Desktop\GTA-RP.VN\Windowns2k8\Windowns2k8\pawno\include\fuckcleo.inc(107) : error 017: undefined symbol "OnVehicleDamageStatusUpdate"
C:\Users\Administrator\Desktop\GTA-RP.VN\Windowns2k8\Windowns2k8\pawno\include\fuckcleo.inc(107) : error 010: invalid function or declaration
Pawn compiler 3.2.3664                          Copyright (c) 1997-2006, ITB CompuPhase


3 Errors.

Include fuckcleo.inc
Code:

/*
 *
 *              "fuckCleo.inc" - #1 Anti-cleo mod include
 *                      Created/Debugged most by Lorenc_
 * 
 *      Thanks to:
 *                        Cessil, Infamous and [FeK]Drakins, JernejL
 *
*/

/* ** Stop Duplicating Code! ** */
#if defined _fcleo_included
        #endinput
#endif
#define _fcleo_included

/* ** Includes ** */
#include                                                        < a_samp >

/* ** Configuration ** */
#define FC_FILE_VERSION                                "0.3.5" // Added the FC_

#define CLEO_FAKEKILL                                ( 1 )
#define CLEO_CARWARP                                ( 2 )
#define CLEO_PLAYERBUGGER                        ( 3 ) // This number will never be called from OnPlayerCleoDetected
#define CLEO_CARSWING                                ( 4 )
#define CLEO_CAR_PARTICLE_SPAM                ( 5 )

/* ** Variables ** */
enum E_CLEO_DATA
{
        E_FK_LASTDEATH,                                        E_FK_DEATHSPAM,       
        E_CW_TIME,                                                E_CW_VEHID,
        Float: E_PB_X,                                        Float: E_PB_Y,                                Float: E_PB_Z,
        E_CPS_SPAMCOUNT,                                E_CPS_TICK
};

static stock
        g_cleoData                                                [ MAX_PLAYERS ] [ E_CLEO_DATA ],
       
        bool: FC_OPU,
        bool: FC_OPD,
        bool: FC_OPSC,
        bool: FC_OVDSU,
        bool: FC_OPDC
;

/* ** Forwards ** */
forward OnPlayerCleoDetected                ( playerid, cleoid );
forward fc_RepairVehicle                        ( vehicleid );

public fc_RepairVehicle( vehicleid )
{
        #if defined _FOREACH_LOCAL_VERSION // I guess this is always defined in foreach.inc
                foreach(Player, playerid)
                {
                        if( GetPlayerVehicleID( playerid ) == vehicleid )  {
                                g_cleoData[ playerid ] [ E_CPS_SPAMCOUNT ]        = 0;
                                g_cleoData[ playerid ] [ E_CPS_TICK ]                = 0;
                        }
                }
        #else
                for( new playerid; playerid < MAX_PLAYERS; playerid++ )
                {
                        if( IsPlayerConnected( playerid ) )
                        {
                                if( GetPlayerVehicleID( playerid ) == vehicleid )  {
                                        g_cleoData[ playerid ] [ E_CPS_SPAMCOUNT ]        = 0;
                                        g_cleoData[ playerid ] [ E_CPS_TICK ]                = 0;
                                }
                        }
                }
        #endif
        return RepairVehicle( vehicleid );
}
#define RepairVehicle fc_RepairVehicle

public OnVehicleDamageStatusUpdate( vehicleid, playerid )
{
        static fc_tires, fc_lights;
    GetVehicleDamageStatus( vehicleid, fc_lights, fc_tires, fc_lights, fc_tires );
        if( GetPlayerState( playerid ) == PLAYER_STATE_DRIVER )
        {
            if( fc_lights || fc_tires )
                return 1;
               
                new time = GetTickCount( );
                switch( time - g_cleoData[ playerid ] [ E_CPS_TICK ] )
                {
                        case 0 .. 500:
                        {
                                g_cleoData[ playerid ] [ E_CPS_SPAMCOUNT ] ++;
                                if( g_cleoData[ playerid ] [ E_CPS_SPAMCOUNT ] >= 10 )
                                {
                                        CallLocalFunction( "OnPlayerCleoDetected", "dd", playerid, CLEO_CAR_PARTICLE_SPAM );
                                        return 1;
                                }
                        }
                        default: g_cleoData[ playerid ] [ E_CPS_SPAMCOUNT ] = 0;
                }
                g_cleoData[ playerid ] [ E_CPS_TICK ] = time;
        }
        return ( FC_OVDSU ) ? CallLocalFunction( "FC_OnVehicleDamageStatusUpdate", "dd", vehicleid, playerid ) : 1;
}

#if defined ALS_OnVehicleDamageStatusUpdate
        #undef OnVehicleDamageStatusUpdate
#else
        #define ALS_OnVehicleDamageStatusUpdate
#endif
#define OnVehicleDamageStatusUpdate FC_OnVehicleDamageStatusUpdate
forward FC_OnVehicleDamageStatusUpdate( vehicleid, playerid );

public OnPlayerStateChange( playerid, newstate, oldstate )
{
    if( newstate == PLAYER_STATE_DRIVER )
    {
        if( GetPlayerVehicleID( playerid ) != g_cleoData[ playerid ] [ E_CW_VEHID ] )
        {
            if( g_cleoData[ playerid ] [ E_CW_TIME ] > gettime( ) )
            {
                                CallLocalFunction( "OnPlayerCleoDetected", "dd", playerid, CLEO_CARWARP );
                return 1;
            }
            g_cleoData[ playerid ] [ E_CW_TIME ] = gettime( ) + 1;
                        g_cleoData[ playerid ] [ E_CW_VEHID ] = GetPlayerVehicleID( playerid );
        }
    }
        return ( FC_OPSC ) ? CallLocalFunction( "FC_OnPlayerStateChange", "ddd", playerid, newstate, oldstate ) : 1;
}

#if defined _ALS_OnPlayerStateChange
        #undef OnPlayerStateChange
#else
        #define _ALS_OnPlayerStateChange
#endif
#define OnPlayerStateChange FC_OnPlayerStateChange
forward FC_OnPlayerStateChange( playerid, newstate, oldstate );

public OnPlayerDeath( playerid, killerid, reason )
{
        new time = gettime( );
        switch( time - g_cleoData[ playerid ] [ E_FK_LASTDEATH ] )
        {
                case 0 .. 3:
                {
                        g_cleoData[ playerid ] [ E_FK_DEATHSPAM ] ++;
                        if( g_cleoData[ playerid ] [ E_FK_DEATHSPAM ] >= 3 )
                        {
                                CallLocalFunction( "OnPlayerCleoDetected", "dd", playerid, CLEO_FAKEKILL );
                                return 1;
                        }
                }
                default: g_cleoData[ playerid ] [ E_FK_DEATHSPAM ] = 0;
        }
        g_cleoData[ playerid ] [ E_FK_LASTDEATH ] = time;
        return ( FC_OPD ) ? CallLocalFunction( "FC_OnPlayerDeath", "ddd", playerid, killerid, reason ) : 1;
}

#if defined _ALS_OnPlayerDeath
        #undef OnPlayerDeath
#else
        #define _ALS_OnPlayerDeath
#endif
#define OnPlayerDeath FC_OnPlayerDeath
forward FC_OnPlayerDeath( playerid, killerid, reason );

public OnPlayerUpdate( playerid )
{
        static
                Float: X,        Float: Y,        Float: Z,
                Float: vX,        Float: vY,        Float: vZ
        ;
        GetPlayerPos( playerid, X, Y, Z );

        if( X >= 99999.0 || Y >= 99999.0 || Z >= 99999.0 || X <= -99999.0 || Y <= -99999.0 || Z <= -99999.0 ) {
                  SendClientMessage( playerid, 0xa9c4e4ff, "Warning: Excessive X, Y, Z has been breached thus last location set." );
                SetPlayerPos( playerid, g_cleoData[ playerid ] [ E_PB_X ], g_cleoData[ playerid ] [ E_PB_Y ], g_cleoData[ playerid ] [ E_PB_Z ] );
        }
        else
        {
            g_cleoData[ playerid ] [ E_PB_X ] = X;
            g_cleoData[ playerid ] [ E_PB_Y ] = Y;
            g_cleoData[ playerid ] [ E_PB_Z ] = Z;
        }

        if( IsPlayerInAnyVehicle( playerid ) && GetPlayerState( playerid ) == PLAYER_STATE_DRIVER )
        {
                GetPlayerPos( playerid, X, Y, Z );
                  GetVehicleVelocity( GetPlayerVehicleID( playerid ), vX, vY, vZ );
                if( ( vX > 3.0 || vY > 3.0 || vZ > 3.0 || vX < -3.0 || vY < -3.0 || vZ < -3.0 ) && ( vX != X && vY != Y && vZ != Z ) )
                {
                        CallLocalFunction( "OnPlayerCleoDetected", "dd", playerid, CLEO_CARSWING );
                }
        }
        return ( FC_OPU ) ? CallLocalFunction( "FC_OnPlayerUpdate", "d", playerid ) : 1;
}

#if defined _ALS_OnPlayerUpdate
        #undef OnPlayerUpdate
#else
        #define _ALS_OnPlayerUpdate
#endif
#define OnPlayerUpdate FC_OnPlayerUpdate
forward FC_OnPlayerUpdate( playerid );

public OnPlayerDisconnect(playerid, reason)
{
        // Pointless reseting, but just incase!
        g_cleoData[ playerid ] [ E_FK_LASTDEATH ] = 0;
        g_cleoData[ playerid ] [ E_FK_DEATHSPAM ] = 0;
        g_cleoData[ playerid ] [ E_CW_TIME ] = 0;
        g_cleoData[ playerid ] [ E_CW_VEHID ] = INVALID_VEHICLE_ID;
        g_cleoData[ playerid ] [ E_PB_X ] = -1;
        g_cleoData[ playerid ] [ E_PB_Y ] = -1;
        g_cleoData[ playerid ] [ E_PB_Z ] = -1;
        g_cleoData[ playerid ] [ E_CPS_SPAMCOUNT ] = 0;
        g_cleoData[ playerid ] [ E_CPS_TICK ] = 0;
        return ( FC_OPDC ) ? CallLocalFunction( "FC_OnPlayerDisconnect", "dd", playerid, reason ) : 1;
}

#if defined _ALS_OnPlayerDisconnect
        #undef OnPlayerDisconnect
#else
        #define _ALS_OnPlayerDisconnect
#endif
#define OnPlayerDisconnect FC_OnPlayerDisconnect
forward FC_OnPlayerDisconnect( playerid, reason );

#if !defined FILTERSCRIPT
        public OnGameModeInit()
        {
                FC_OPU = ( funcidx( "FC_OnPlayerUpdate" ) != -1 );
                FC_OPD = ( funcidx( "FC_OnPlayerDeath" ) != -1 );
                FC_OPSC = ( funcidx( "FC_OnPlayerStateChange" ) != -1 );
                FC_OPDC = ( funcidx( "FC_OnPlayerDisconnect" ) != -1 );
                FC_OVDSU = ( funcidx( "FC_OnVehicleDamageStatusUpdate" ) != -1 );
                return ( funcidx( "FC_OnGameModeInit" ) != -1 ) ? CallLocalFunction( "FC_OnGameModeInit", "" ) : 1;
        }       
        #if defined _ALS_OnGameModeInit
                #undef OnGameModeInit
        #else
                #define _ALS_OnGameModeInit
        #endif
        #define OnGameModeInit FC_OnGameModeInit
        forward FC_OnGameModeInit();
#else
        public OnFilterScriptInit()
        {
                FC_OPU = ( funcidx( "FC_OnPlayerUpdate" ) != -1 );
                FC_OPD = ( funcidx( "FC_OnPlayerDeath" ) != -1 );
                FC_OPSC = ( funcidx( "FC_OnPlayerStateChange" ) != -1 );
                FC_OPDC = ( funcidx( "FC_OnPlayerDisconnect" ) != -1 );
                FC_OVDSU = ( funcidx( "FC_OnVehicleDamageStatusUpdate" ) != -1 );
                return ( funcidx( "FC_OnFilterScriptInit" ) != -1 ) ? CallLocalFunction( "FC_OnFilterScriptInit", "" ) : 1;
        }       
        #if defined _ALS_OnFilterScriptInit
                #undef OnFilterScriptInit
        #else
                #define _ALS_OnFilterScriptInit
        #endif
        #define OnFilterScriptInit FC_OnFilterScriptInit
        forward FC_OnFilterScriptInit();
#endif

2 . Include strlib.inc
Code:

#include <a_samp>

#if !defined STRLIB_BUFFER_SIZE
        #define STRLIB_BUFFER_SIZE  2048
#endif

#if !defined STRLIB_RETURN_SIZE
        #define STRLIB_RETURN_SIZE  128
#endif

#if !defined STRLIB_USE_FORMATEX
        #if defined __fmt_funcinc
                #if !defined FormatSpecifier
                        #error Please include formatex before strlib.
                #endif
       
                #define STRLIB_USE_FORMATEX  true
        #else
                #define STRLIB_USE_FORMATEX  false
        #endif
#endif

// Used in strtrim (deprecated)
enum trim_edges {
        trim_left  = 1,
        trim_right = 2,
        trim_both = trim_left | trim_right
};

// Used in strtrim and strpad
enum string_edges {
        edge_left  = 1,
        edge_right = 2,
        edge_both = edge_left | edge_right
};

/*
 * Returns a formatted string.
 *
 * Parameters:
 *  fmat[] - The format string.
 *  ... - The format variables.
 *
 * Returns:
 *  The formatted string.
 */
forward sprintf(const fmat[], {Float, _}:...);

/*
 * Get the first character of a string
 *
 * Parameters:
 *  string[] - The string.
 *
 * Returns:
 *  The first character of the string.
 */
forward strgetfirstc(const string[]);

/*
 * Get a character from a specific index in a string.
 *
 * Parameters:
 *  string[] - The string.
 *  index - The position in the string.
 *
 * Returns:
 *  The character at that index, or '\0' if out of range.
 */
forward strgetc(const string[], index);

/*
 * Get the size of a string.
 *
 * Parameters:
 *  string[] - The string.
 *
 * Returns:
 *  The size of the string, in bytes.
 */
forward strsize(const string[]);

/*
 * Find out if a string is empty.
 *
 * Parameters:
 *  string[] - The string.
 *
 * Returns:
 *  True if empty, otherwise false.
 */
forward bool:isempty(const string[]);

/*
 * Compare two strings.
 *
 * Parameters:
 *  str1[] - The first string.
 *  str2[] - The second string.
 *  ignorecase - Whether to compare them in a case-insensitive manner.
 *
 * Returns:
 *  True if equal, otherwise false.
 */
forward bool:isequal(const str1[], const str2[], bool:ignorecase = false);

/*
 * Split a string by a given delimiter.
 *
 * Parameters:
 *  output[][] - A multi-dimensional array that will be filled with substrings.
 *  input[] - The input string to split.
 *  delimiter[] - The delimiter to split by. Defaults to ",".
 *  limit - The max. no. substrings.
 *  trim - Whether to trim the substrings from whitespace. Defaults to true.
 *  ignorecase - Whether the search for "delimiter" should be case-insensitive.
 *  size1 - The size of the 1st dimension of output (otput[this][]). Defaults to sizeof(output).
 *  size2 - The size of the 2nd dimension of output (otput[][this]). Defaults to sizeof(output[]).
 *
 * Returns:
 *  The number of substrings that were copied into the array.
 */
forward strexplode(output[][], const input[], const delimiter[] = !",", limit = cellmax, bool:trim = true, bool:ignorecase = false, size1 = sizeof(output), size2 = sizeof(output[]));

/*
 * Glue together strings into one.
 *
 * Parameters:
 *  glue[] - The string that will be between all other strings.
 *  output[] - The output string.
 *  maxlength - The size of "output". Defaults to sizeof(output).
 *  ...[] - Strings to glue together.
 *
 * Returns:
 *  Nothing
 */
forward strimplode(const glue[], output[], maxlength = sizeof(output), ...);

/*
 * Replace occurrences of the search string with the replacement string.
 *
 * Parameters:
 *  string[] - The string to perform the replacing in.
 *  search[] - The string to look for.
 *  replacement[] - The string to put instead of "search".
 *  ignorecase - Whether the search for "search" should be case-insensitive. Defaults to false.
 *  pos - The position to start at. Defaults to 0 (the beginning).
 *  limit - Limit the number of replacements. Defaults to -1 (no limit).
 *  maxlength - The size of "string". Defaults to sizeof(string).
 *
 * Returns:
 *  The number of replacements that were made.
 */
forward strreplace(string[], const search[], const replacement[], bool:ignorecase = false, pos = 0, limit = -1, maxlength = sizeof(string));

/*
 * Trim whitespace or a specific group of characters from a string.
 *
 * Parameters:
 *  string[] - The string to trim.
 *  chars[] - A string with characters to trim, or all whitespace if empty. Default is all whitespace.
 *  edge - The edge(s) to trim (edge_left/edge_right/edge_both). Default is edge_both.
 *
 * Returns:
 *  Nothing
 */
forward strtrim(string[], const chars[] = !"", string_edges:edge = edge_both);

/*
 * Pad edge(s) of a string with spaces.
 *
 * Parameters:
 *  string[] - The string to pad.
 *  length - The new length of the string.
 *  substr[] - The substring to pad with. Defaults to a space (" ").
 *  edge - The edge(s) to pad (edge_left/edge_right/edge_both). Default is edge_both.
 *  trim_first - Whether to trim the string before padding.
 *  trim_chars[] - The chars to trim, defaults is all whitespace.
 *  maxlength - The size of "string". Defaults to sizeof(string).
 *  input - Used internally.
 */
forward strpad(string[], length, const substr[] = !" ", string_edges:edge = edge_both, bool:trim_first = true, const trim_chars[] = !"", maxlength = sizeof(string), const input[] = !"");

/*
 * Wrap a string inside two other strings.
 *
 * Parameters:
 *  left[] - The string on the left side.
 *  string[] - The middle string that will be modified.
 *  right[] - The string on the right side.
 *  maxlength - The size of "string". Defaults to sizeof(string).
 */
forward strwrap(const left[], string[], const right[], maxlength = sizeof(string));

/*
 * Count substrings.
 *
 * Parameters:
 *  string[] - The string to search inside.
 *  sub[] - The string to search for.
 *  ignorecase - Whether the search should be case-insensitive.
 *  count_overlapped - Whether to count overlapping strings ("abcabc" in "abcabcabc" will count 2 instead of 1).
 *
 * Returns:
 *  The number of occurrences of "sub" in "string".
 */
forward strcount(const string[], const sub[], bool:ignorecase = false, bool:count_overlapped = false);

/*
 * Read a string from a PAWN string literal.
 *
 * Parameters:
 *  output[] - The variable to save into.
 *  input[] - The string literal.
 *  pos - The position in "input" to start reading from. Will be modified to the end of the literal.
 *  maxlength - The size of "output". Defaults to sizeof(output).
 *
 * Returns:
 *  true on success, false on error.
 */
forward bool:strfromliteral(output[], const input[], &pos = 0, maxlength = sizeof(output));

/*
 * Build a PAWN string literal from a given string.
 *
 * Parameters:
 *  output[] - The variable to save into.
 *  substrings[] - The string to build from.
 *  maxlength - The size of "output". Defaults to sizeof(output).
 *
 * Returns:
 *  Nothing
 */
forward strtoliteral(output[], const input[], maxlength = sizeof(output), bool:paranoid = true);

/*
 * Convert an array to a string.
 *
 * Example: {0x1122, 0x5566} becomes "0000112200005566".
 *
 * Parameters:
 *  output[] - The variable to save into.
 *  input[] - The array to build from.
 *  inputlength - The size of "input". Defaults to sizeof(input).
 *  maxlength - The size of "output". Defaults to sizeof(output).
 *
 * Returns:
 *  Nothing
 */
forward strfrombin(output[], const input[], inputlength = sizeof(input), maxlength = sizeof(output));

/*
 * Convert a string to an array.
 *
 * Example: "0000112200005566" becomes {0x1122, 0x5566}.
 *
 * Parameters:
 *  output[] - The variable to save into.
 *  input[] - The array to build from.
 *  maxlength - The size of "output". Defaults to sizeof(output).
 *
 * Returns:
 *  The length of the output, in cells.
 */
forward strtobin(output[], const input[], maxlength = sizeof(output));

/*
 * Concatenate one string with a part of another.
 *
 * Parameters:
 *  dest[] - The variable to concatenate the other part with.
 *  source[] - The string to extract from.
 *  start - The start offset, defaults to 0.
 *  end - The start offset, defaults to end of string.
 *  maxlength - The size of "dest". Defaults to sizeof(dest).
 */
forward strcatmid(dest[], const source[], start = 0, end = -1, maxlength = sizeof(dest));

/*
 * UTF-8 encode a string. Characters above 127 will be encoded into
 * two or more characters.
 *
 * Parameters:
 *  dest[] - The output variable.
 *  source[] - The string to encode.
 *  maxlength - The size of "dest". Defaults to sizeof(dest).
 */
forward utf8encode(dest[], const source[], maxlength = sizeof(dest));

/*
 * UTF-8 decode a string. UTF-8 characters will be collapsed into single
 * characters in the array.
 *
 * Parameters:
 *  dest[] - The output variable.
 *  source[] - The string to encode.
 *  maxlength - The size of "dest". Defaults to sizeof(dest).
 */
forward utf8decode(dest[], const source[], maxlength = sizeof(dest));

/*
 * Decode an encoded URL.
 *
 * Parameters:
 *  output[] - The output variable.
 *  input[] - The string to decode.
 *  maxlength - The size of "output". Defaults to sizeof(output).
 */
forward strurldecode(output[], const input[], maxlength = sizeof(output));

/*
 * URL encode a string.
 *
 * Parameters:
 *  output[] - The output variable.
 *  input[] - The string to encode.
 *  maxlength - The size of "output". Defaults to sizeof(output).
 *  pack - Whether to pack the output. Defaults to false.
 */
forward strurlencode(output[], const input[], maxlength = sizeof(output), bool:pack = false);

// Same as above, but output is returned
forward ret_strcatmid(const string[], const source[], start = 0, end = -1);
forward ret_strfrombin(const input[], inputlength = sizeof(input));
forward ret_strimplode(const glue[], ...);
forward ret_strreplace(const string[], const search[], const replacement[], bool:ignorecase = false, pos = 0, limit = -1);
forward ret_strfromliteral(const input[], &pos = 0);
forward ret_strtoliteral(const input[], bool:paranoid = true);
forward ret_strtrim(const string[], const chars[] = !"", string_edges:edge = edge_both);
forward ret_strpad(const string[], length, const substr[] = !" ", string_edges:edge = edge_both, bool:trim_first = true, const trim_chars[] = !"");
forward ret_strwrap(const left[], const string[], const right[]);
forward ret_strurldecode(const input[]);
forward ret_strurlencode(const input[], bool:pack = false);
forward ret_utf8encode(const input[]);
forward ret_utf8decode(const input[]);

// Return from native functions
forward ret_strpack(const source[]);
forward ret_strunpack(const source[]);
forward ret_strcat(const string1[], const string2[]);
forward ret_strmid(const source[], start, end);
forward ret_strins(const string[], const substr[], pos, maxlength = sizeof(string));
forward ret_strdel(const string[], start, end);
forward ret_valstr(value, bool:pack = false);

forward ret_GetPlayerName(playerid, bool:pack = false);


stock
        // Used throughout the library
        g_StrlibBuffer[2048]
;

// Workaround for compiler bug
forward _strlib_funcinc();
public _strlib_funcinc() {
        new temp[1];
       
        format(!"", 0, !"");
        strcat(temp, temp);
        strpack(temp, temp);
        strunpack(temp, temp);
}

// Internal functions
static stock RedirectArgument(arg, ...) {
        #emit LOAD.S.pri  0
        #emit ADD.C      12
        #emit LOAD.S.alt  arg
        #emit SHL.C.alt  2
        #emit ADD
        #emit MOVE.alt
        #emit LOAD.S.pri  16
        #emit STOR.I
}

static stock CopyArgumentToHeap(arg, bool:pack = false, const argptr[] = "") {
        new arg_address, address;
       
        #emit LOAD.S.pri  0
        #emit ADD.C      12
        #emit LOAD.S.alt  arg
        #emit SHL.C.alt  2
        #emit ADD
        #emit LOAD.I
        #emit STOR.S.pri  arg_address
        #emit STOR.S.pri  argptr
       
        if (pack) {
                new bytes = ((strlen(argptr) + 1 + 3) / 4) * 4;
               
                #emit LCTRL      2
                #emit STOR.S.pri  address
                #emit LOAD.S.alt  bytes
                #emit ADD
                #emit SCTRL      2
               
                //strpack(dest[], const source[], maxlength = sizeof dest)
                #emit LOAD.S.pri  bytes
                #emit SHR.C.pri  2
                #emit PUSH.pri
               
                #emit PUSH.S      arg_address
                #emit PUSH.S      address
               
                #emit PUSH.C      12
               
                #emit SYSREQ.C    strpack
                #emit STACK      16
        } else {
                new bytes = (strlen(argptr) + 1) * 4;
               
                #emit LCTRL      2
                #emit STOR.S.pri  address
                #emit LOAD.S.alt  bytes
                #emit ADD
                #emit SCTRL      2
               
                //strunpack(dest[], const source[], maxlength = sizeof dest)
                #emit LOAD.S.pri  bytes
                #emit SHR.C.pri  2
                #emit PUSH.pri
               
                #emit PUSH.S      arg_address
                #emit PUSH.S      address
               
                #emit PUSH.C      12
               
                #emit SYSREQ.C    strunpack
                #emit STACK      16
        }
       
        #emit LOAD.S.pri  0
        #emit ADD.C      12
        #emit LOAD.S.alt  arg
        #emit SHL.C.alt  2
        #emit ADD
        #emit MOVE.alt
        #emit LOAD.S.pri  address
        #emit STOR.I
       
        return address;
}

static stock RestoreHeapToAddress(address) {
        #emit LOAD.S.pri  address
        #emit SCTRL      2
}

static stock IsOverlapping(const str1[], size1 = sizeof(str1), const str2[], size2 = sizeof(str2)) {
        new addr1, addr2;
       
        if (size1 == -1) {
                size1 = strsize(str1);
        } else {
                size1 *= 4;
        }
       
        if (size2 == -1) {
                size2 = strsize(str2);
        } else {
                size2 *= 4;
        }
       
        #emit LOAD.S.pri  str1
        #emit STOR.S.pri  addr1
        #emit LOAD.S.pri  str2
        #emit STOR.S.pri  addr2

        return (addr1 < addr2 + size2) && (addr2 < addr1 + size1);
}

// strlib functions
#define ispacked(%1) \
        ((%1)[0] > 255)

stock strgetfirstc(const string[]) {
        return ispacked(string) ? string{0} : string[0];
}

stock strgetc(const string[], index) {
        if (index < 0)
                return '\0';
       
        new len = strlen(string);
       
        if (index >= len)
                return '\0';
       
        return ispacked(string) ? string{index} : string[index];
}

stock strsize(const string[]) {
        new len = strlen(string);
       
        if (ispacked(string))
                return len + 1;
       
        return (len + 1) * 4;
}

stock bool:isempty(const string[]) {
        if (ispacked(string))
                return string{0} == '\0';
        else
                return string[0] == '\0';
}

stock bool:isequal(const str1[], const str2[], bool:ignorecase = false) {
    new
        c1 = (str1[0] > 255) ? str1{0} : str1[0],
        c2 = (str2[0] > 255) ? str2{0} : str2[0]
    ;

    if (!c1 != !c2)
        return false;

    return !strcmp(str1, str2, ignorecase);
}

stock strimplode(const glue[], output[], maxlength = sizeof(output), ...) {
        new args = numargs();
       
        // Null-out "output"
        output[0] = '\0';
       
        // Loop the variable arguments (the ones after "maxlength").
        for (new arg = 3; arg < args; arg++) {
                // If this isn't the first string, append the glue.
                if (arg != 3)
                        strcat(output, glue, maxlength);
               
                // Wrap these in braces or they will be a part of the above if statement (compiler bug)
                {
                        // Get the address of argument no. <arg>
                        #emit LCTRL      5
                        #emit ADD.C      12
                        #emit LOAD.S.alt  arg
                        #emit SHL.C.alt  2
                        #emit ADD
                        #emit LOAD.I
                       
                        // Push the maxlength, arg address, and output address
                        #emit PUSH.S      maxlength
                        #emit PUSH.pri
                        #emit PUSH.S      output
                       
                        // Push the argument count
                        #emit PUSH.C      12
                       
                        // call strcat
                        #emit SYSREQ.C    strcat
                       
                        // Restore the stack
                        #emit STACK      16
                }
        }
}

stock strexplode(output[][], const input[], const delimiter[] = !",", limit = cellmax, bool:trim = true, bool:ignorecase = false, size1 = sizeof(output), size2 = sizeof(output[])) {
        if (!size1 || !size2) {
                printf("(strexplode) ERROR: size1 = %d, size2 = %d. Can't be 0.", size1, size2);
               
                return 0;
        }
       
        if (isempty(delimiter)) {
                print(!"(strexplode) ERROR: delimiter is empty.");
               
                return 0;
        }
       
        if (trim) {
                new i = -1;
               
                if (ispacked(input)) {
                        while (input{++i}) {
                                if (input{i} > ' ') {
                                        i = -1;
                                       
                                        break;
                                }
                        }
                } else {
                        while (input[++i]) {
                                if (input[i] > ' ') {
                                        i = -1;
                                       
                                        break;
                                }
                        }
                }
               
                if (i != -1)
                        return 0;
        } else if (isempty(input)) {
                return 0;
        }
       
        if (limit == 0) {
                return 0;
        } else if (limit == cellmax) {
                limit = 0;
        }
       
        new
                    pos = 0,
                    next,
                bool:packed = ispacked(input),
                    dlen = strlen(delimiter),
                    count = 0,
                    end
        ;
       
        while (pos != -1) {
                ++count;
               
                if (limit > 0 && count >= limit) {
                        next = -1;
                } else {
                        next = strfind(input, delimiter, ignorecase, pos);
                }
               
                end = (next == -1) ? cellmax : next;
               
                if (trim) {
                        if (end == cellmax)
                                end = strlen(input);
                       
                        if (packed) {
                                while (0 < input{pos} <= ' ') pos++;
                                while (end > 0 && input{end - 1} <= ' ') end--;
                        } else {
                                while (0 < input[pos] <= ' ') pos++;
                                while (end > 0 && input[end - 1] <= ' ') end--;
                        }
                }
               
                strmid(output[count - 1], input, pos, end, size2);
               
                if (count >= size1 || next == -1 || (limit < 0 && count >= -limit))
                        break;
               
                pos = next + dlen;
        }
       
        return count;
}

stock strreplace(string[], const search[], const replacement[], bool:ignorecase = false, pos = 0, limit = -1, maxlength = sizeof(string)) {
    // No need to do anything if the limit is 0.
    if (limit == 0)
        return 0;
   
    new
            sublen = strlen(search),
            replen = strlen(replacement),
        bool:packed = ispacked(string),
            maxlen = maxlength,
            len = strlen(string),
            count = 0
    ;
   
   
    // "maxlen" holds the max string length (not to be confused with "maxlength", which holds the max. array size).
    // Since packed strings hold 4 characters per array slot, we multiply "maxlen" by 4.
    if (packed)
        maxlen *= 4;
   
    // If the length of the substring is 0, we have nothing to look for..
    if (!sublen)
        return 0;
   
    // In this line we both assign the return value from "strfind" to "pos" then check if it's -1.
    while (-1 != (pos = strfind(string, search, ignorecase, pos))) {
        // Delete the string we found
        strdel(string, pos, pos + sublen);
       
        len -= sublen;
       
        // If there's anything to put as replacement, insert it. Make sure there's enough room first.
        if (replen && len + replen < maxlen) {
            strins(string, replacement, pos, maxlength);
           
            pos += replen;
            len += replen;
        }
       
        // Is there a limit of number of replacements, if so, did we break it?
        if (limit != -1 && ++count >= limit)
            break;
    }
   
    return count;
}

stock strtrim(string[], const chars[] = !"", string_edges:edge = edge_both) {
        new bool:packed = ispacked(string);
       
        // If "chars" is empty, trim whitespace
        if (!strgetfirstc(chars)) {
                // Should the left side be trimmed?
                if (edge & edge_left) {
                        new i = 0;
                       
                        if (packed)
                                while (0 < string{i} <= ' ') i++;
                        else
                                while (0 < string[i] <= ' ') i++;
                       
                        if (i) {
                                strdel(string, 0, i);
                        }
                }
               
                // Should the right side be trimmed?
                if (edge & edge_right) {
                        new i = strlen(string);
                       
                        if (i) {
                                if (packed) {
                                        while (--i && 0 < string{i} <= ' ') {}
                                       
                                        string{i + 1} = '\0';
                                } else {
                                        while (--i && 0 < string[i] <= ' ') {}
                                       
                                        string[i + 1] = '\0';
                                }
                        }
                }
        } else {
                // Should the left side be trimmed?
                if (edge & edge_left) {
                        new i = 0, sub[2];
                       
                        if (packed) {
                                while ((sub[0] = string{i})) {
                                        if (strfind(chars, sub) == -1)
                                                break;
                                       
                                        i++;
                                }
                               
                                if (i) {
                                        strdel(string, 0, i);
                                }
                        } else {
                                while ((sub[0] = string[i])) {
                                        if (strfind(chars, sub) == -1)
                                                break;
                                       
                                        i++;
                                }
                               
                                if (i) strdel(string, 0, i);
                        }
                }
               
                // Should the right side be trimmed?
                if (edge & edge_right) {
                        new i = strlen(string), sub[2];
                       
                        if (i >= 0) {
                                if (packed) {
                                        while (i--) {
                                                sub[0] = string{i};
                                               
                                                if (strfind(chars, sub) == -1)
                                                        break;
                                        }
                                       
                                        string{i + 1} = '\0';
                                } else {
                                        while (i--) {
                                                sub[0] = string[i];
                                               
                                                if (strfind(chars, sub) == -1)
                                                        break;
                                        }
                                       
                                        string[i + 1] = '\0';
                                }
                        }
                }
        }
}

stock strpad(string[], length, const substr[] = !" ", string_edges:edge = edge_both, bool:trim_first = true, const trim_chars[] = !"", maxlength = sizeof(string), const input[] = !"") {
        if (trim_first) {
                strtrim(string, trim_chars, edge);
        }
       
        new
                    heap,
                    length_left = 0,
                    length_right = 0,
                    len = strlen(string),
                    sublen = strlen(substr),
                bool:packed,
                bool:subpacked = ispacked(substr)
        ;
       
        if (len > length)
                return;
        else
                length -= len;
       
        // Make "input" a pointer to "string"
        #emit LOAD.S.pri  string
        #emit STOR.S.pri  input
       
        // Copy "input" to the heap so it won't be linked to "string" anymore.
        heap = CopyArgumentToHeap(7);
       
        string[0] = '\0';
        len = 0;
       
        switch (edge) {
                case edge_left:
                        length_left = length;
                case edge_right:
                        length_right = length;
                default:
                        length_left = length / 2, length_right = length - length_left;
        }
       
        if (length_left) {
                while (len < length_left) {
                        if (subpacked)
                                strcat(string, substr, length_left * 4);
                        else
                                strcat(string, substr, length_left + 1);
               
                        len += sublen;
                }
       
                if (subpacked)
                        string{length_left} = 0;
        }
       
        strcat(string, input, maxlength);
       
        if (length_right) {
                len = strlen(string);
                length_right += len;
                packed = ispacked(string);
               
                while (len < length_right) {
                        if (packed)
                                strcat(string, substr, length_right / 4 + 1);
                        else
                                strcat(string, substr, length_right + 1);
               
                        len += sublen;
                }
               
                if (packed)
                        string{length_right + 1} = 0;
        }
       
        RestoreHeapToAddress(heap);
}

stock strwrap(const left[], string[], const right[], maxlength = sizeof(string)) {
        strins(string, left, 0, maxlength);
        strcat(string, right, maxlength);
}

stock strcount(const string[], const sub[], bool:ignorecase = false, bool:count_overlapped = false) {
        new
                increment = count_overlapped ? 1 : strlen(sub),
                pos = -increment,
                count = 0
        ;
       
       
        while (-1 != (pos = strfind(string, sub, ignorecase, pos + increment)))
                count++;
       
        return count;
}

stock bool:strfromliteral(output[], const input[], &pos = 0, maxlength = sizeof(output)) {
        new
                    length = strlen(input),
                        c,
                        outlen = 0,
                    heap = 0
        ;

        // No need to do anything else.
        if (!length)
                return true;
       
        if (IsOverlapping(output, maxlength, input, -1))
                heap = CopyArgumentToHeap(1);
       
        output[0] = '\0';
       
        if (input[0] == '"')
                pos++;

        for (;; pos++) {
                if (outlen >= maxlength - 1 || pos >= length)
                        break;
               
                c = input[pos];
               
                switch (c) {
                        // String ended
                        case '"': break;
                        case '\\': {}
                        default: {
                                output[outlen++] = c;

                                continue;
                        }
                }

                // String ends with a backslash - invalid.
                if (pos == length - 1)
                        goto return_false;

                // We're after a backslash now, let's see what's there.
                c = input[++pos];

                switch (c) {
                        case '"',
                            '\'',
                            '\\',
                            '%': output[outlen++] = c;
                        case 'a': output[outlen++] = '\a';
                        case 'b': output[outlen++] = '\b';
                        case 'e': output[outlen++] = '\e';
                        case 'f': output[outlen++] = '\f';
                        case 'r': output[outlen++] = '\r';
                        case 'n': output[outlen++] = '\n';
                        case 't': output[outlen++] = '\t';
                        case 'v': output[outlen++] = '\v';
                       
                        case 'x': {
                                new val = 0;

                                // String ends with "\x" - invalid.
                                if (c == length - 1)
                                        goto return_false;

                                while ((c = input[pos + 1])) {
                                        if ('a' <= c <= 'f' || 'A' <= c <= 'F') {
                                                val = (val << 4) + (tolower(c) - 'a' + 10);
                                        } else if ('0' <= c <= '9') {
                                                val = (val << 4) + (c - '0');
                                        } else {
                                                break;
                                        }

                                        pos++;
                                }

                                if (c == ';')
                                        pos++;

                                output[outlen++] = val;
                        }
                       
                        case '0' .. '9': {
                                new val = 0;

                                while ((c = input[pos])) {
                                        if ('0' <= c <= '9') {
                                                val = val * 10 + (c - '0');
                                        } else {
                                                break;
                                        }

                                        pos++;
                                }

                                if (c != ';') pos--;

                                output[outlen++] = val;
                        }
                       
                        default: {
                                goto return_false;
                        }
                }
        }

        output[outlen] = '\0';
       
        pos++;
       
        new bool:ret = true;
       
        goto return_true;
return_false:
        ret = false;
return_true:

        if (heap)
                RestoreHeapToAddress(heap);

        return ret;
}

stock strtoliteral(output[], const input[], maxlength = sizeof(output), bool:paranoid = true) {
        new i, c, outlen, heap = 0;
       
        if (IsOverlapping(output, maxlength, input, -1))
                heap = CopyArgumentToHeap(1);
       
        output[outlen++] = '"';

        for (i = 0; (c = input[i]); i++) {
                if (maxlength - outlen <= 3) {
                        outlen = min(outlen, maxlength - 2);
                       
                        break;
                }
               
                switch (c) {
                        case ' ', '!', '#' .. '[', ']', '^' .. '~':
                                output[outlen++] = c;

                        case  '"': strunpack(output[outlen], !"\\\"", 3), outlen += 2;
                        case '\a': strunpack(output[outlen], !"\\a" , 3), outlen += 2;
                        case '\b': strunpack(output[outlen], !"\\b" , 3), outlen += 2;
                        case '\e': strunpack(output[outlen], !"\\e" , 3), outlen += 2;
                        case '\f': strunpack(output[outlen], !"\\f" , 3), outlen += 2;
                        case '\r': strunpack(output[outlen], !"\\r" , 3), outlen += 2;
                        case '\n': strunpack(output[outlen], !"\\n" , 3), outlen += 2;
                        case '\t': strunpack(output[outlen], !"\\t" , 3), outlen += 2;
                        case '\v': strunpack(output[outlen], !"\\v" , 3), outlen += 2;
                        case '\\': strunpack(output[outlen], !"\\\\" , 3), outlen += 2;
                       
                        default: {
                                if (!paranoid && 0x80 <= c <= 0xFF) {
                                        output[outlen++] = c;
                                        continue;
                                }
                               
                                if (maxlength - outlen <= 8)
                                        break;
                               
                                format(output[outlen], 7, "\\x%03x;", c);

                                outlen += 6;
                        }
                }
        }

        output[outlen++] = '"';
        output[outlen] = '\0';
       
        if (heap)
                RestoreHeapToAddress(heap);
}

stock strfrombin(output[], const input[], inputlength = sizeof(input), maxlength = sizeof(output)) {
        static const hex_chars[] = "0123456789ABCDEF";
        new outlen = 0, heap = 0;
       
        if (IsOverlapping(output, maxlength, input, -1))
                heap = CopyArgumentToHeap(1);
       
        for (new i = 0; i < inputlength; i++) {
                if (maxlength - outlen <= 7) {
                        outlen = min(outlen, maxlength - 1);
                       
                        break;
                }
               
                new input_cell = input[i];
               
                output[outlen++] = hex_chars[(input_cell            ) >>> 28];
                output[outlen++] = hex_chars[(input_cell & 0x0F000000) >>> 24];
                output[outlen++] = hex_chars[(input_cell & 0x00F00000) >>> 20];
                output[outlen++] = hex_chars[(input_cell & 0x000F0000) >>> 16];
                output[outlen++] = hex_chars[(input_cell & 0x0000F000) >>> 12];
                output[outlen++] = hex_chars[(input_cell & 0x00000F00) >>>  8];
                output[outlen++] = hex_chars[(input_cell & 0x000000F0) >>>  4];
                output[outlen++] = hex_chars[(input_cell & 0x0000000F)      ];
        }
       
        output[outlen] = '\0';
       
        if (heap)
                RestoreHeapToAddress(heap);
}

stock strtobin(output[], const input[], maxlength = sizeof(output)) {
        new len = strlen(input), outlen = 0, heap = 0;
       
        if (IsOverlapping(output, maxlength, input, -1))
                heap = CopyArgumentToHeap(1);
       
        for (new i = 0; i < len;) {
                if (outlen >= maxlength || i > len - 8) {
                        break;
                }
               
                new c, out = 0;
               
                #define ADD_OUT(%1) \
                        c = input[i++]; out |= (('a' <= c <= 'f' || 'A' <= c <= 'F') ? (tolower(c) - 'a' + 10) : (c - '0')) << %1
               
                ADD_OUT(28);
                ADD_OUT(24);
                ADD_OUT(20);
                ADD_OUT(16);
                ADD_OUT(12);
                ADD_OUT(8);
                ADD_OUT(4);
                ADD_OUT(0);
               
                #undef ADD_OUT
               
                output[outlen++] = out;
        }
       
        if (heap)
                RestoreHeapToAddress(heap);
       
        return outlen;
}

stock strurlencode(output[], const input[], maxlength = sizeof(output), bool:pack = false) {
        static const hex_chars[] = "0123456789ABCDEF";
       
        new
                    len = strlen(input),
                bool:packed = ispacked(input),
                    outlen = 0,
                    heap = 0
        ;
       
        if (IsOverlapping(output, maxlength, input, -1))
                heap = CopyArgumentToHeap(1, packed);
       
        if (pack)
                maxlength *= 4;
       
        for (new i = 0; i < len; i++) {       
                if (maxlength - outlen <= 1)
                        break;
               
                new c = packed ? input{i} : input[i];
               
                switch (c) {
                        case 'a' .. 'z', 'A' .. 'Z', '0' .. '9', '_': {
                                if (pack)
                                        output{outlen++} = c;
                                else
                                        output[outlen++] = c;
                        }
                       
                        case ' ': {
                                if (pack)
                                        output{outlen++} = '+';
                                else
                                        output[outlen++] = '+';
                        }
                       
                        default: {
                                if (maxlength - outlen <= 3)
                                        break;
                               
                                if (pack) {
                                        output{outlen++} = '%';
                                        output{outlen++} = hex_chars[(c & 0xF0) >>> 4];
                                        output{outlen++} = hex_chars[c & 0x0F];
                                } else {
                                        output[outlen++] = '%';
                                        output[outlen++] = hex_chars[(c & 0xF0) >>> 4];
                                        output[outlen++] = hex_chars[c & 0x0F];
                                }
                        }
                }
        }
       
        if (pack)
                output{outlen} = '\0';
        else
                output[outlen] = '\0';
       
        if (heap)
                RestoreHeapToAddress(heap);
}

stock strurldecode(output[], const input[], maxlength = sizeof(output)) {
        new prev_pos = 0, pos = 0, inputlen = strlen(input), len, heap = 0;
       
        if (IsOverlapping(output, maxlength, input, -1))
                heap = CopyArgumentToHeap(1);
       
        output[0] = '\0';
       
        while (-1 != (pos = strfind(input, "%", _, pos))) {
                static str[2];
                new c;
               
                if (prev_pos != pos) {
                        len = strlen(output);
                       
                        strcatmid(output, input, prev_pos, pos, maxlength);
                        strreplace(output, "+", " ", _, len, _, maxlength);
                }
               
                if (inputlen < pos + 3)
                        goto func_end;
               
                str[0] = 0;
               
                c = input[pos + 1]; str[0] |= (('a' <= c <= 'f' || 'A' <= c <= 'F') ? (tolower(c) - 'a' + 10) : (c - '0')) << 4;
                c = input[pos + 2]; str[0] |= (('a' <= c <= 'f' || 'A' <= c <= 'F') ? (tolower(c) - 'a' + 10) : (c - '0'));
               
                strcat(output, str, maxlength);
               
                prev_pos = (pos += 3);
        }
       
        len = strlen(output);
       
        strcatmid(output, input, prev_pos, _, maxlength);
        strreplace(output, "+", " ", _, len, _, maxlength);

func_end:
        if (heap)
                RestoreHeapToAddress(heap);
}

stock strcatmid(dest[], const source[], start = 0, end = -1, maxlength = sizeof(dest)) {
        new heap = 0;
       
        if (IsOverlapping(dest, maxlength, source, -1))
                heap = CopyArgumentToHeap(1);
       
        if (start == 0 && end == -1) {
                strcat(dest, source, maxlength);
        } else {
                if (end == -1)
                        end = strlen(source);
               
                if (ispacked(dest)) {
                        new len = strlen(dest);
                       
                        if (ispacked(source)) {
                                strunpack(g_StrlibBuffer, source);
                       
                                strcat(dest, g_StrlibBuffer[start], min(maxlength, (len + end - start) / 4 + 1));
                        } else {       
                                strcat(dest, source[start], min(maxlength, (len + end - start) / 4 + 1));
                        }
                       
                        dest{len + end - start} = '\0';
                } else {
                        if (ispacked(source)) {
                                strunpack(g_StrlibBuffer, source);
                       
                                strcat(dest, g_StrlibBuffer[start], min(maxlength, strlen(dest) + end - start + 1));
                        } else {       
                                strcat(dest, source[start], min(maxlength, strlen(dest) + end - start + 1));
                        }
                }
        }
       
        if (heap)
                RestoreHeapToAddress(heap);
}

stock utf8encode(dest[], const source[], maxlength = sizeof(dest)) {
        new heap = 0;
       
        if (IsOverlapping(dest, maxlength, source, -1)) {
                heap = CopyArgumentToHeap(1);
        }
       
        new len = strlen(source);
        new packed = ispacked(source);
       
        dest[0] = '\0';
       
        new idx = 0;
       
        for (new i = 0; i < len; i++) {
                new c = packed ? source{i} : source[i];
               
                if (c >= 0x80) {
                        if (c > 0x4000000) {
                                // 6 byte
                                dest[idx++] = 0b11111100 | ((c >>> 30) & 0b00000001);
                                dest[idx++] = 0b10000000 | ((c >>> 24) & 0b00111111);
                                dest[idx++] = 0b10000000 | ((c >>> 18) & 0b00111111);
                                dest[idx++] = 0b10000000 | ((c >>> 12) & 0b00111111);
                                dest[idx++] = 0b10000000 | ((c >>> 6) & 0b00111111);
                                dest[idx++] = 0b10000000 | (c & 0b00111111);
                        } else if (c > 0x200000) {
                                // 5 byte
                                dest[idx++] = 0b11111000 | ((c >>> 24) & 0b00000011);
                                dest[idx++] = 0b10000000 | ((c >>> 18) & 0b00111111);
                                dest[idx++] = 0b10000000 | ((c >>> 12) & 0b00111111);
                                dest[idx++] = 0b10000000 | ((c >>> 6) & 0b00111111);
                                dest[idx++] = 0b10000000 | (c & 0b00111111);
                        } else if (c > 0x10000) {
                                // 4 byte
                                dest[idx++] = 0b11110000 | ((c >>> 18) & 0b00000111);
                                dest[idx++] = 0b10000000 | ((c >>> 12) & 0b00111111);
                                dest[idx++] = 0b10000000 | ((c >>> 6) & 0b00111111);
                                dest[idx++] = 0b10000000 | (c & 0b00111111);
                        } else if (c > 0x800) {
                                // 3 byte
                                dest[idx++] = 0b11100000 | ((c >>> 12) & 0b00001111);
                                dest[idx++] = 0b10000000 | ((c >>> 6) & 0b00111111);
                                dest[idx++] = 0b10000000 | (c & 0b00111111);
                        } else {
                                // 2 byte
                                dest[idx++] = 0b11000000 | ((c >>> 6) & 0b00011111);
                                dest[idx++] = 0b10000000 | (c & 0b00111111);
                               
                        }
                } else if (c > 0) {
                        dest[idx++] = c;
                }
        }
       
        dest[idx++] = '\0';
       
        if (heap) {
                RestoreHeapToAddress(heap);
        }
}

stock utf8decode(dest[], const source[], maxlength = sizeof(dest)) {
        new heap = 0;
       
        if (IsOverlapping(dest, maxlength, source, -1)) {
                heap = CopyArgumentToHeap(1);
        }
       
        new len = strlen(source);
       
        dest[0] = '\0';
       
        new idx = 0;
       
        for (new i = 0; i < len; i++) {
                new c = source[i];
               
                if (c & 0b10000000) {
                        if (c & 0b11100000 == 0b11000000) {
                                // 2 byte
                                if (i + 3 >= len) continue;
                               
                                dest[idx++] = (c & 0b00011111) << 6 | (source[++i] & 0b00111111);
                        } else if (c & 0b11110000 == 0b11100000) {
                                // 3 byte
                                if (i + 4 >= len) continue;
                               
                                dest[idx++] = (c & 0b00001111) << 12 |
                                              (source[++i] & 0b00111111) << 6 |
                                              (source[++i] & 0b00111111);
                        } else if (c & 0b11111000 == 0b11110000) {
                                // 4 byte
                                if (i + 5 >= len) continue;
                               
                                dest[idx++] = (c & 0b00000111) << 18 |
                                              (source[++i] & 0b00111111) << 12 |
                                              (source[++i] & 0b00111111) << 6 |
                                              (source[++i] & 0b00111111);
                        } else if (c & 0b11111100 == 0b11111000) {
                                // 5 byte
                                if (i + 6 >= len) continue;
                               
                                dest[idx++] = (c & 0b00000011) << 24 |
                                              (source[++i] & 0b00111111) << 18 |
                                              (source[++i] & 0b00111111) << 12 |
                                              (source[++i] & 0b00111111) << 6 |
                                              (source[++i] & 0b00111111);
                        } else if (c & 0b11111110 == 0b11111100) {
                                // 6 byte
                                if (i + 7 >= len) continue;
                               
                                dest[idx++] = (c & 0b00000001) << 30 |
                                              (source[++i] & 0b00111111) << 24 |
                                              (source[++i] & 0b00111111) << 18 |
                                              (source[++i] & 0b00111111) << 12 |
                                              (source[++i] & 0b00111111) << 6 |
                                              (source[++i] & 0b00111111);
                        }
                } else {
                        dest[idx++] = c;
                }
        }
       
        dest[idx++] = 0;
       
        if (heap) {
                RestoreHeapToAddress(heap);
        }
}


stock ret_strcatmid(const string[], const source[], start = 0, end = -1) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, string);
       
        strcatmid(output, source, start, end);
       
        return output;
}

stock ret_strfrombin(const input[], inputlength = sizeof(input)) {
        new output[STRLIB_RETURN_SIZE];
       
        strfrombin(output, input, inputlength);
       
        return output;
}

stock ret_strimplode(const glue[], ...) {
        new output[STRLIB_RETURN_SIZE];
        const maxlength = sizeof(output);
        new args = numargs();
       
        // Loop the variable arguments (the ones after "maxlength").
        for (new arg = 1; arg < args; arg++) {
                // If this isn't the first string, append the glue.
                if (arg != 1)
                        strcat(output, glue, maxlength);
               
                // Wrap these in braces or they will be a part of the above if statement (compiler bug)
                {
                        // Get the address of argument no. <arg>
                        #emit LCTRL      5
                        #emit ADD.C      12
                        #emit LOAD.S.alt  arg
                        #emit SHL.C.alt  2
                        #emit ADD
                        #emit LOAD.I
                       
                        // Push the maxlength, arg address, and output address
                        #emit PUSH.C      maxlength
                        #emit PUSH.pri
                        #emit PUSH.ADR    output
                       
                        // Push the argument count
                        #emit PUSH.C      12
                       
                        // call strcat
                        #emit SYSREQ.C    strcat
                       
                        // Restore the stack
                        #emit STACK      16
                }
        }
       
        // Fix compiler bug (returning strings in variadic functions)
        #emit LOAD.S.pri  8
        #emit ADD.C      12
        #emit MOVE.alt
        #emit LCTRL      5
        #emit ADD
        #emit LOAD.I
        #emit STOR.S.pri  20
       
        return output;
}

stock ret_strreplace(const string[], const search[], const replacement[], bool:ignorecase = false, pos = 0, limit = -1) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, string);
       
        strreplace(output, search, replacement, ignorecase, pos, limit);
       
        return output;
}

stock ret_strfromliteral(const input[], &pos = 0) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, input);
       
        strfromliteral(output, input, pos);
       
        return output;
}

stock ret_strtoliteral(const input[], bool:paranoid = true) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, input);
       
        strtoliteral(output, input, paranoid);
       
        return output;
}

stock ret_strtrim(const string[], const chars[] = !"", string_edges:edge = edge_both) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, string);
       
        strtrim(output, chars, edge);
       
        return output;
}

stock ret_strpad(const string[], length, const substr[] = !" ", string_edges:edge = edge_both, bool:trim_first = true, const trim_chars[] = !"") {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, string);
       
        strpad(output, length, substr, edge, trim_first, trim_chars);
       
        return output;
}

stock ret_strwrap(const left[], const string[], const right[]) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, left);
        strcat(output, string);
        strcat(output, right);
       
        return output;
}

stock ret_strurldecode(const input[]) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, input);
       
        strurldecode(output, input);
       
        return output;
}

stock ret_strurlencode(const input[], bool:pack = false) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, input);
       
        strurlencode(output, input, _, pack);
       
        return output;
}

stock ret_utf8encode(const input[]) {
        new output[STRLIB_RETURN_SIZE];
       
        utf8encode(output, input);
       
        return output;
}

stock ret_utf8decode(const input[]) {
        new output[STRLIB_RETURN_SIZE];
       
        utf8decode(output, input);
       
        return output;
}

stock ret_strpack(const source[]) {
        new output[STRLIB_RETURN_SIZE];
       
        strpack(output, source);
       
        return output;
}

stock ret_strunpack(const source[]) {
        new output[STRLIB_RETURN_SIZE];
       
        strunpack(output, source);
       
        return output;
}

stock ret_strcat(const string1[], const string2[]) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, string1);
        strcat(output, string2);
       
        return output;
}

stock ret_strmid(const source[], start, end) {
        new output[STRLIB_RETURN_SIZE];
       
        strmid(output, source, start, end);
       
        return output;
}

stock ret_strins(const string[], const substr[], pos, maxlength = sizeof(string)) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, string);
        strins(output, substr, pos);
       
        return output;
}

stock ret_strdel(const string[], start, end) {
        new output[STRLIB_RETURN_SIZE];
       
        strcat(output, string);
        strdel(output, start, end);
       
        return output;
}

stock ret_valstr(value, bool:pack = false) {
        new output[STRLIB_RETURN_SIZE];
       
        format(output, sizeof(output), "%d", value);
       
        if (pack)
                strpack(output, output);
       
        return output;
}

stock ret_GetPlayerName(playerid, bool:pack = false) {
        new output[MAX_PLAYER_NAME];
       
        GetPlayerName(playerid, output, sizeof(output));
       
        if (pack)
                strpack(output, output);
       
        return output;
}

stock sprintf(const fmat[], {Float, _}:...) {
        static output[STRLIB_RETURN_SIZE], frm_header[3], heap;
       
        const output_size = sizeof(output);
       
        if (ispacked(fmat)) {
                heap = CopyArgumentToHeap(0);
        } else {
                heap = 0;
        }{}
       
        // Store current frame header
        #emit LCTRL      5
        #emit CONST.alt  frm_header
        #emit MOVS      12
       
        // Change the stack pointer to FRM + 12
        #emit ADD.C    12 // pri is FRM (see above)
        #emit SCTRL    4
       
        // Push sizeof(output)
        #emit PUSH.C      output_size
       
        // Push output
        #emit PUSH.C      output
       
        // Push the argument count
        #emit LOAD.S.pri  8
        #emit ADD.C      8
        #emit PUSH.pri
       
        #if !STRLIB_USE_FORMATEX
                const formatex = 0; // Dummy used to avoid "unknown symbol" error
               
                goto do_sysreq;
        #endif

        // Call formatex (unless this was skipped above)
        #emit LCTRL      6
        #emit ADD.C      36
        #emit PUSH.pri
        #emit CONST.pri  formatex
        #emit SCTRL      6
       
        #if !STRLIB_USE_FORMATEX
                do_sysreq:
        #endif
       
        // Call format (unless formatex was called, in which case this is skipped)
        #emit SYSREQ.C    format
       
        // Restore the stack pointer to FRM
        #emit LCTRL      5
        #emit SCTRL      4
       
        // Copy back the frame header
        #emit MOVE.alt
        #emit CONST.pri  frm_header
        #emit MOVS        12
       
        // Restore heap if needed
        if (heap) {
                RestoreHeapToAddress(heap);
        }{}
       
        // IMPORTANT: Fix compiler bug (returning strings in variadic functions)
        #emit LOAD.S.pri  8
        #emit ADD.C      12
        #emit MOVE.alt
        #emit LCTRL      5
        #emit ADD
        #emit LOAD.I
        #emit STOR.S.pri  20 // 16 + (static_args * 4)
       
        return output;
       
        // It is actually used, just not by its symbol name
        #pragma unused fmat
}


Viewing all articles
Browse latest Browse all 18226

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>