/* snprintf.h --

   This file is part of the UPX executable compressor.

   Copyright (C) Markus Franz Xaver Johannes Oberhumer
   Copyright (C) Laszlo Molnar
   All Rights Reserved.

   UPX and the UCL library are free software; you can redistribute them
   and/or modify them under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of
   the License, or (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; see the file COPYING.
   If not, write to the Free Software Foundation, Inc.,
   59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

   Markus F.X.J. Oberhumer              Laszlo Molnar
   <markus@oberhumer.com>               <ezerotven+github@gmail.com>
 */

#pragma once

/*************************************************************************
// UPX version of string functions, with assertions and sane limits
**************************************************************************/

noinline upx_rsize_t upx_safe_strlen(const char *) may_throw;

// info: snprintf() returns length and NOT size, but max_size is indeed size (incl NUL)

noinline int upx_safe_vsnprintf(char *str, upx_rsize_t max_size, const char *format, va_list ap)
    may_throw;
noinline int upx_safe_snprintf(char *str, upx_rsize_t max_size, const char *format, ...)
    may_throw attribute_format(3, 4);

// malloc's *ptr
noinline int upx_safe_vasprintf(char **ptr, const char *format, va_list ap) may_throw;
noinline int upx_safe_asprintf(char **ptr, const char *format, ...)
    may_throw attribute_format(2, 3);

// returns a malloc'd pointer
noinline char *upx_safe_xprintf(const char *format, ...) may_throw attribute_format(1, 2);

//
// noexcept variants (these use "assert_noexcept")
//

noinline char *upx_safe_strdup_noexcept(const char *) noexcept;
noinline upx_rsize_t upx_safe_strlen_noexcept(const char *) noexcept;
noinline int upx_safe_vsnprintf_noexcept(char *str, upx_rsize_t max_size, const char *format,
                                         va_list ap) noexcept;
noinline int upx_safe_snprintf_noexcept(char *str, upx_rsize_t max_size, const char *format,
                                        ...) noexcept attribute_format(3, 4);

//
// globally redirect some functions
//

#undef strdup
#define strdup upx_safe_strdup_noexcept

#undef strlen
#define strlen upx_safe_strlen

#undef snprintf
#undef sprintf
#undef vsnprintf
#define snprintf  upx_safe_snprintf
#define sprintf   ERROR_sprintf_IS_DANGEROUS_USE_snprintf
#define vsnprintf upx_safe_vsnprintf

/*************************************************************************
// some uchar string support functions to avoid casts
**************************************************************************/

forceinline uchar *upx_safe_strdup_noexcept(const uchar *s) noexcept {
    return (uchar *) upx_safe_strdup_noexcept((const char *) s);
}

forceinline upx_rsize_t upx_safe_strlen(const uchar *s) may_throw {
    return upx_safe_strlen((const char *) s);
}
forceinline upx_rsize_t upx_safe_strlen_noexcept(const uchar *s) noexcept {
    return upx_safe_strlen_noexcept((const char *) s);
}

forceinline uchar *strcpy(uchar *s1, const uchar *s2) noexcept {
    return (uchar *) strcpy((char *) s1, (const char *) s2);
}

forceinline int strcmp(const uchar *s1, const char *s2) noexcept {
    return strcmp((const char *) s1, s2);
}
forceinline int strcmp(const char *s1, const uchar *s2) noexcept {
    return strcmp(s1, (const char *) s2);
}
forceinline int strcmp(const uchar *s1, const uchar *s2) noexcept {
    return strcmp((const char *) s1, (const char *) s2);
}

forceinline int strcasecmp(const uchar *s1, const char *s2) noexcept {
    return strcasecmp((const char *) s1, s2);
}
forceinline int strcasecmp(const char *s1, const uchar *s2) noexcept {
    return strcasecmp(s1, (const char *) s2);
}
forceinline int strcasecmp(const uchar *s1, const uchar *s2) noexcept {
    return strcasecmp((const char *) s1, (const char *) s2);
}

/* vim:set ts=4 sw=4 et: */
