/*
 * Source reconstruction for script cvar builtins.
 *
 * Binary SHA-256:
 * 4d2391c10e234559ace294fb69d96741cad522653c361f13f626f4dc1891acb7
 */

#include <stdint.h>
#include <string.h>

#include "recovered_game.h"
#include "scr_vm.h"

/*
 * The binary zeroes a 1,024-byte clean buffer but lets the sanitizing loop
 * write as many as 8,192 bytes. The original extent and overflow are
 * preserved; see
 * original-bugs/game-script-cvar-clean-buffer-overflow.md.
 */
#define SCRIPT_CVAR_VALUE_BUFFER_SIZE 1024
#define SCRIPT_CVAR_SANITIZE_LIMIT 8192

void trap_Cvar_VariableStringBuffer(const char *name, char *buffer, int size);
int trap_Cvar_VariableIntegerValue(const char *name);
float trap_Cvar_VariableValue(const char *name);
void trap_Cvar_Register(vmCvar_t *cvar, const char *name, const char *value,
                        int flags);
void trap_Cvar_Set(const char *name, const char *value);
int Q_CleanCharacter(int value);

static const char *game_compat_script_cvar_get_value_arg(char messageBuffer[SCRIPT_CVAR_VALUE_BUFFER_SIZE])
{
    /* NOT_FROM_ORIGINAL_SOURCE: factored from setcvar/makecvarserverinfo bodies. */
    if (Scr_GetType(1) == SCRIPT_VAR_LOCALIZED_STRING) {
        Scr_ConstructMessageString(1, messageBuffer,
                                   SCRIPT_CVAR_VALUE_BUFFER_SIZE,
                                   SCRIPT_MESSAGE_MODE_CVAR_VALUE);
        return messageBuffer;
    }

    return Scr_GetString(1);
}

static void game_compat_script_cvar_build_observed_clean_buffer(
    const char *value,
    char cleaned[SCRIPT_CVAR_VALUE_BUFFER_SIZE])
{
    /* NOT_FROM_ORIGINAL_SOURCE: factored from setcvar/makecvarserverinfo bodies.
     * ORIGINAL_BINARY_BUG: the destination is only 1,024 bytes although the
     * loop permits 8,192 writes; see
     * original-bugs/game-script-cvar-clean-buffer-overflow.md. */
    memset(cleaned, 0, SCRIPT_CVAR_VALUE_BUFFER_SIZE);

    for (int index = 0; index < SCRIPT_CVAR_SANITIZE_LIMIT && value[index] != '\0';
         index++) {
        cleaned[index] = Q_CleanCharacter((int)value[index]);
        if (cleaned[index] == '"') {
            cleaned[index] = '\'';
        }
    }
}

/* VERIFIED_DECOMPILER(0x6721f, 7721f_script_func_getcvar.c, VERIFY-SCRIPT-CVAR-PACKET-2026-06-17): DATAFLOW_VERIFIED - cvar name fetch, 1024-byte buffer lookup, Scr_AddString argument, and void return checked against current decompiler output. */
void GScr_GetCvar(void)
{
    const char *name = Scr_GetString(0);
    char value[SCRIPT_CVAR_VALUE_BUFFER_SIZE];

    trap_Cvar_VariableStringBuffer(name, value, SCRIPT_CVAR_VALUE_BUFFER_SIZE);
    Scr_AddString(value);
}

/* VERIFIED_DECOMPILER(0x67277, 77277_script_func_getcvarint.c, VERIFY-SCRIPT-CVAR-PACKET-2026-06-17): DATAFLOW_VERIFIED - cvar name fetch, integer lookup, Scr_AddInt argument, and void return checked against current decompiler output. */
void GScr_GetCvarInt(void)
{
    const char *name = Scr_GetString(0);

    Scr_AddInt(trap_Cvar_VariableIntegerValue(name));
}

/* VERIFIED_DECOMPILER(0x672b1, 772b1_script_func_getcvarfloat.c, VERIFY-SCRIPT-CVAR-PACKET-2026-06-17): DATAFLOW_VERIFIED - cvar name fetch, float lookup, Scr_AddFloat argument, and void return checked against current decompiler output. */
void GScr_GetCvarFloat(void)
{
    const char *name = Scr_GetString(0);

    Scr_AddFloat(trap_Cvar_VariableValue(name));
}

/* VERIFIED_DECOMPILER(0x672eb, 772eb_script_func_setcvar.c, VERIFY-SCRIPT-CVAR-PACKET-2026-06-17): DATAFLOW_VERIFIED - string/message value argument, strlen side effect, observed clean-buffer loop, optional serverinfo flag, register call, set call, and void return checked against current decompiler output. */
void GScr_SetCvar(void)
{
    const char *name = Scr_GetString(0);
    char messageValue[SCRIPT_CVAR_VALUE_BUFFER_SIZE];
    char cleaned[SCRIPT_CVAR_VALUE_BUFFER_SIZE];
    const char *value = game_compat_script_cvar_get_value_arg(messageValue);
    int flags = CVAR_FLAG_SCRIPT_SETCVAR;

    (void)strlen(value);
    game_compat_script_cvar_build_observed_clean_buffer(value, cleaned);

    if (Scr_GetNumParam() > 2 && Scr_GetBool(2)) {
        flags |= CVAR_FLAG_SCRIPT_SETCVAR_SERVERINFO;
    }

    trap_Cvar_Register(0, name, value, flags);
    trap_Cvar_Set(name, value);
}

/* VERIFIED_DECOMPILER(0x6e4ae, 7e4ae_script_func_makecvarserverinfo.c, VERIFY-SCRIPT-CVAR-PACKET-2026-06-17): DATAFLOW_VERIFIED - string/message value argument, strlen side effect, observed clean-buffer loop, serverinfo registration flags, and void return checked against current decompiler output. */
void GScr_MakeCvarServerInfo(void)
{
    const char *name = Scr_GetString(0);
    char messageValue[SCRIPT_CVAR_VALUE_BUFFER_SIZE];
    char cleaned[SCRIPT_CVAR_VALUE_BUFFER_SIZE];
    const char *value = game_compat_script_cvar_get_value_arg(messageValue);

    (void)strlen(value);
    game_compat_script_cvar_build_observed_clean_buffer(value, cleaned);

    trap_Cvar_Register(0, name, value,
                       CVAR_FLAG_SCRIPT_MAKE_SERVERINFO);
}
