/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2014-2020. All rights reserved.
 * Licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 * Description: By defining corresponding macro for ANSI string and including "output.inl",
 *              this file generates real underlying function used by printf family API.
 * Author: lishunda
 * Create: 2014-02-25
 */

#define SECUREC_FORMAT_OUTPUT_INPUT 1

#ifdef SECUREC_FOR_WCHAR
#undef SECUREC_FOR_WCHAR
#endif

#include "secureprintoutput.h"
#if SECUREC_WARP_OUTPUT
#define SECUREC_FORMAT_FLAG_TABLE_SIZE 128
SECUREC_INLINE const char *SecSkipKnownFlags(const char *format)
{
    static const unsigned char flagTable[SECUREC_FORMAT_FLAG_TABLE_SIZE] = {
        /*
         * Known flag is  "0123456789 +-#hlLwZzjqt*I$"
         */
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x01, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x01, 0x00, 0x00,
        0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00,
        0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00
    };
    const char *fmt = format;
    while (*fmt != '\0') {
        char fmtChar = *fmt;
        if ((unsigned char)fmtChar > 0x7f) { /* 0x7f is upper limit of format char value */
            break;
        }
        if (flagTable[(unsigned char)fmtChar] == 0) {
            break;
        }
        ++fmt;
    }
    return fmt;
}

SECUREC_INLINE int SecFormatContainN(const char *format)
{
    const char *fmt = format;
    while (*fmt != '\0') {
        ++fmt;
        /* Skip normal char */
        if (*(fmt - 1) != '%') {
            continue;
        }
        /* Meet %% */
        if (*fmt == '%') {
            ++fmt; /* Point to  the character after the %. Correct handling %%xx */
            continue;
        }
        /* Now parse %..., fmt point to the character after the % */
        fmt = SecSkipKnownFlags(fmt);
        if (*fmt == 'n') {
            return 1;
        }
    }
    return 0;
}
/*
 * Multi character formatted output implementation, the count include \0 character, must be greater than zero
 */
int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList)
{
    int retVal;
    if (SecFormatContainN(format) != 0) {
        string[0] = '\0';
        return -1;
    }
    retVal = vsnprintf(string, count, format, argList);
    if (retVal >= (int)count) { /* The size_t to int is ok, count max is SECUREC_STRING_MAX_LEN */
        /* The buffer was too small; we return truncation */
        string[count - 1] = '\0';
        return SECUREC_PRINTF_TRUNCATE;
    }
    if (retVal < 0) {
        string[0] = '\0'; /* Empty the dest strDest */
        return -1;
    }
    return retVal;
}
#else
#if SECUREC_IN_KERNEL
#include <linux/ctype.h>
#endif

#ifndef EOF
#define EOF (-1)
#endif

#include "output.inl"

/*
 * Multi character formatted output implementation
 */
int SecVsnprintfImpl(char *string, size_t count, const char *format, va_list argList)
{
    SecPrintfStream str;
    int retVal;

    str.count = (int)count; /* The count include \0 character, must be greater than zero */
    str.cur = string;

    retVal = SecOutputS(&str, format, argList);
    if (retVal >= 0) {
        if (SecPutZeroChar(&str) == 0) {
            return retVal;
        }
    }
    if (str.count < 0) {
        /* The buffer was too small, then truncate */
        string[count - 1] = '\0';
        return SECUREC_PRINTF_TRUNCATE;
    }
    string[0] = '\0'; /* Empty the dest string */
    return -1;
}

/*
 * Write a wide character
 */
SECUREC_INLINE void SecWriteMultiChar(char ch, int num, SecPrintfStream *f, int *pnumwritten)
{
    int count;
    for (count = num; count > 0; --count) {
        --f->count; /* f -> count may be negative,indicating insufficient space */
        if (f->count < 0) {
            *pnumwritten = -1;
            return;
        }
        *(f->cur) = ch;
        ++f->cur;
        *pnumwritten = *pnumwritten + 1;
    }
}

/*
 * Write string function, where this function is called, make sure that len is greater than 0
 */
SECUREC_INLINE void SecWriteString(const char *string, int len, SecPrintfStream *f, int *pnumwritten)
{
    const char *str = string;
    int count;
    for (count = len; count > 0; --count) {
        --f->count; /* f -> count may be negative,indicating insufficient space */
        if (f->count < 0) {
            *pnumwritten = -1;
            return;
        }
        *(f->cur) = *str;
        ++f->cur;
        ++str;
    }
    *pnumwritten = *pnumwritten + (int)(size_t)(str - string);
}
#endif

