/**
* @file memops.c
*
* @brief Exposes a handful of libc-lite utility functions used by other
*        modules.
*
* Copyright (c) 2022, NVIDIA CORPORATION. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of NVIDIA CORPORATION nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/

#include <stddef.h>
#include <stdint.h>
#include <misc/ct-assert.h>
#include <misc/macros.h>

#include <cpu/type-conversion.h>
#include <libc-lite/libc.h>

START_RFD_BLOCK(MISRA, DEVIATE, Rule_1_2, "Approval: Bug 200531996, DR: SWE-FSP-009-SWSADR.docx",
                MISRA, DEVIATE, Directive_4_6, "Approval: Bug 200543266, DR: SWE-FSP-003-SWSADR.docx",
                MISRA, DEVIATE, Directive_4_9, "Approval: Bug 200531995, DR: SWE-FSP-012-SWSADR.docx",
                MISRA, DEVIATE, Rule_21_2, "Approval: Jira TID-1970, DR: SWE-FSP-066-SWSADR.docx",
                CERTC, DEVIATE, DCL37_C, "Approval: Bug 2731179, DR: SWE-FSP-067-SWSADR.docx")


void *memcpy(void *dst, const void *src, size_t n)
{
    START_RFD_BLOCK(MISRA, DEVIATE, Rule_11_5, "Approval: Bug 200542277, DR:  SWE-FSP-024-SWSADR.docx")
    char *d = (char *)(dst);
    const char *s = (const char *)(src);
    END_RFD_BLOCK(MISRA, DEVIATE, Rule_11_5, "Approval: Bug 200542277, DR:  SWE-FSP-024-SWSADR.docx")

    // CERTC INT30 fix - integer wrap-around
    // MISRA RULE 14.4 fix - return essential boolean type
    for (size_t j=n; j > 0U ; j--)
    {
        *d = *s;

        // MISRA RULE 13.3 fix - increment separated from pointer dereference
        d++;
        s++;
    }

    return dst;
}

int memcmp(const void *s1, const void *s2, size_t n)
{
    START_RFD_BLOCK(MISRA, DEVIATE, Rule_11_5, "Approval: Bug 200542277, DR:  SWE-FSP-024-SWSADR.docx")
    const uint8_t *d = (const uint8_t *)(s1);
    const uint8_t *s = (const uint8_t *)(s2);
    END_RFD_BLOCK(MISRA, DEVIATE, Rule_11_5, "Approval: Bug 200542277, DR:  SWE-FSP-024-SWSADR.docx")
    int32_t cmp = 0;

    // CERTC INT30 fix - integer wrap-around
    // MISRA RULE 14.4 fix - return essential boolean type
    for (size_t j=n ; j > 0U ; j--)
    {
        // MISRA RULE 10.3 fix - explicit conversion to int32_t
        int32_t x = (int32_t)(*s) - (int32_t)(*d);

        // MISRA RULE 14.4 fix - return essential boolean type
        if (x != 0)
        {
            // MISRA RULE 15.5 fix - temp var to pass to return statement
            cmp = x;
            break;
        }

        // MISRA RULE 13.3 fix - increment separated from pointer dereference
        d++;
        s++;
    }

    return cmp;
}

void *memset(void *s, int c, size_t n)
{
    INLINE_RFD(MISRA, DEVIATE, Rule_11_5, "Approval: Bug 200542277, DR:  SWE-FSP-024-SWSADR.docx");
    uint8_t *p = (uint8_t *)(s);
    uint8_t set_c;

    // check "c" and clip to max value if out of bounds
    if (c > UINT8_MAX)
    {
        set_c = UINT8_MAX;
    }
    else
    {
        set_c = (uint8_t)c;
    }

    // CERTC INT30 fix - integer wrap-around
    // MISRA RULE 14.4 fix - return essential boolean type
    for (size_t j=n ; j > 0U ; j--)
    {
        *p = set_c;

        // MISRA RULE 13.3 fix - increment separated from pointer dereference
        p++;
    }

    return s;
}

END_RFD_BLOCK(MISRA, DEVIATE, Rule_1_2, "Approval: Bug 200531996, DR: SWE-FSP-009-SWSADR.docx",
              MISRA, DEVIATE, Directive_4_6, "Approval: Bug 200543266, DR: SWE-FSP-003-SWSADR.docx",
              MISRA, DEVIATE, Directive_4_9, "Approval: Bug 200531995, DR: SWE-FSP-012-SWSADR.docx",
              MISRA, DEVIATE, Rule_21_2, "Approval: Jira TID-1970, DR: SWE-FSP-066-SWSADR.docx",
              CERTC, DEVIATE, DCL37_C, "Approval: Bug 2731179, DR: SWE-FSP-067-SWSADR.docx")
