/*******************************************************************************
 * Copyright IBM Corp. and others 1991
 *
 * This program and the accompanying materials are made available under
 * the terms of the Eclipse Public License 2.0 which accompanies this
 * distribution and is available at https://www.eclipse.org/legal/epl-2.0/
 * or the Apache License, Version 2.0 which accompanies this distribution and
 * is available at https://www.apache.org/licenses/LICENSE-2.0.
 *
 * This Source Code may also be made available under the following
 * Secondary Licenses when the conditions for such availability set
 * forth in the Eclipse Public License, v. 2.0 are satisfied: GNU
 * General Public License, version 2 with the GNU Classpath
 * Exception [1] and GNU General Public License, version 2 with the
 * OpenJDK Assembly Exception [2].
 *
 * [1] https://www.gnu.org/software/classpath/license.html
 * [2] https://openjdk.org/legal/assembly-exception.html
 *
 * SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 OR GPL-2.0-only WITH OpenJDK-assembly-exception-1.0
 *******************************************************************************/

#ifndef OMRUTIL_H_INCLUDED
#define OMRUTIL_H_INCLUDED

/*
 * @ddr_namespace: default
 */

/**
* This file contains public function prototypes and
* type definitions for the util_core module.
*
*/

#include "omrcomp.h"
#include "omrport.h"
#include "omr.h"
#include "pool_api.h"

#ifdef __cplusplus
extern "C" {
#endif

#define OPTION_OK 0
#define OPTION_MALFORMED -1
#define OPTION_OVERFLOW -2
#define OPTION_ERROR -3
#define OPTION_BUFFER_OVERFLOW -4
#define OPTION_OUTOFRANGE -5

#if defined(J9ZOS390)
#pragma map(getdsa, "GETDSA")
/* ----------------- omrgetdsa.s ---------------- */
/**
 * Returns the caa and dsa respectively on z/OS
 */
void *getdsa(void);
#endif


/* ---------------- utf8decode.c ---------------- */

/**
* @brief
* @param input
* @param result
* @return uint32_t
*/
uint32_t
decodeUTF8Char(const uint8_t *input, uint16_t *result);


/**
* @brief
* @param input
* @param result
* @param bytesRemaining
* @return uint32_t
*/
uint32_t
decodeUTF8CharN(const uint8_t *input, uint16_t *result, uintptr_t bytesRemaining);


/* ---------------- utf8encode.c ---------------- */

/**
* @brief
* @param unicode
* @param result
* @return uint32_t
*/
uint32_t
encodeUTF8Char(uintptr_t unicode, uint8_t *result);


/**
* @brief
* @param unicode
* @param result
* @param bytesRemaining
* @return uint32_t
*/
uint32_t
encodeUTF8CharN(uintptr_t unicode, uint8_t *result, uint32_t bytesRemaining);



/* ---------------- xml.c ---------------- */

/**
 * Escapes a string for use with XML.
 * @param portLibrary[in]
 * @param outBuf[out] A buffer in which to place the escaped string.
 * @param outBufLen[in] The length of the output buffer.
 * @param string[in] The string that should be escaped.
 * @param StringLen[in] The length of the string excluding any null termination.
 * @return The number of characters of the input string that were processed before filling the output buffer.
 */
uintptr_t
escapeXMLString(OMRPortLibrary *portLibrary, char *outBuf, uintptr_t outBufLen, const char *string, uintptr_t stringLen);



/* ----------------- primeNumberHelper.c ---------------- */
/*
 * PRIMENUMBERHELPER_OUTOFRANGE is used when primeNumberHelper functions are being used
 * by a number that is not in the supported range of primeNumberHelper.
 * For such cases, these functions return PRIMENUMBERHELPER_OUTOFRANGE.
 */
#define PRIMENUMBERHELPER_OUTOFRANGE 1
/**
 * @brief
 * @param number
 * @return uintptr_t
 */
uintptr_t findLargestPrimeLessThanOrEqualTo(uintptr_t number);

/**
 * @brief
 * @param number
 * @return uintptr_t
 */
uintptr_t findSmallestPrimeGreaterThanOrEqualTo(uintptr_t number);

/**
 * @brief
 * @param void
 * @return uintptr_t
 */
uintptr_t getSupportedBiggestNumberByPrimeNumberHelper(void);

#if defined(OMR_OS_WINDOWS)
/* ---------------- omrgetdbghelp.c ---------------- */

/**
* @brief Load the version of dbghelp.dll that shipped with the JRE. If we can't find the shipped version, try to find it somewhere else.
* @return A handle to dbghelp.dll if we were able to find one, NULL otherwise.
*/
uintptr_t omrgetdbghelp_loadDLL(void);

/**
* @brief Get a previously loaded version of dbghelp.dll that shipped with the JRE.
* @return A handle to dbghelp.dll if we were able to find a previously loaded version, NULL otherwise.
*/
uintptr_t omrgetdbghelp_getDLL(void);

/**
* @brief Free the supplied version of dbgHelpDLL
* @param dbgHelpDLL
* @return 0 if the library was freed, non-zero otherwise.
*/
void omrgetdbghelp_freeDLL(uintptr_t dbgHelpDLL);

#endif  /* defined(OMR_OS_WINDOWS) */

/* ---------------- stricmp.c ---------------- */

/*
 * Converts characters to lowercase.
 * This is intended only to be used for command line processing.
 * Although currently implemented to do ASCII conversion,
 * it may be changed in the future if additional behavior is required.
 * This is used to address locale issues such as in Turkish where
 * the uppercase of 'i' does not equal 'I'.
 *
 *
 * @param c input character
 * @return lowercase version or returns input if a valid ASCII
 *         character wasn't given.
 */
int
j9_cmdla_tolower(int c);

/*
 * Converts ASCII character to lowercase.
 * This is used to address locale issues such as in Turkish where
 * the uppercase of 'i' does not equal 'I'.
 *
 * @param c input character
 * @return lowercase version or returns input if a valid ASCII
 *         character wasn't given.
 */
int
j9_ascii_tolower(int c);

/*
 * Converts characters to uppercase.
 * This is intended only to be used for command line processing.
 * Although currently implemented to do ASCII conversion,
 * it may be changed in the future if additional behavior is required.
 * This is used to address locale issues such as in Turkish where
 * the uppercase of 'i' does not equal 'I'.
 *
 * @param c input character
 * @return uppercase version or returns input if a valid ASCII
 *         character wasn't given.
 */
int
j9_cmdla_toupper(int c);

/*
 * Converts ASCII character to uppercase.
 * This is used to address locale issues such as in Turkish where
 * the uppercase of 'i' does not equal 'I'.
 *
 * @param c input character
 * @return uppercase version or returns input if a valid ASCII
 *         character wasn't given.
 */
int
j9_ascii_toupper(int c);

/*
 * Compare the bytes of two strings, ignoring case. Intended to be used
 * with command line arguments.
 * This is used to address locale issues such as in Turkish where
 * the uppercase of 'i' does not equal 'I'.
 *
 * @param *s1 string1
 * @param *s2 string2
 * @return a positive integer if s1 is greater, zero if the strings
 *         are equal, or a negative value if s1 is less.
 */
int
j9_cmdla_stricmp(const char *s1, const char *s2);

/*
 * Compare the bytes of two strings, ignoring case. Intended to be used
 * with command line arguments.
 * This is used to address locale issues such as in Turkish where
 * the uppercase of 'i' does not equal 'I'.
 *
 * @param *s1 string1
 * @param *s2 string2
 * @param length of string
 * @return a positive integer if s1 is greater, zero if the strings
 *         are equal, or a negative value if s1 is less.
 */
int
j9_cmdla_strnicmp(const char *s1, const char *s2, size_t length);

/* ---------------- argscan.c ---------------- */

/**
* @brief
* @param **scan_start
* @param *search_string
* @return uintptr_t
*/
uintptr_t try_scan(char **scan_start, const char *search_string);


/* ---------------- detectVMDirectory.c ---------------- */
#if defined(OMR_OS_WINDOWS)
/**
 * @brief Detect the directory where the VM library or executable resides.
 *
 * Uses the glue function OMR_Glue_GetVMDirectoryToken().
 *
 * @param[in,out] vmDirectory The buffer to where the VM directory will be written. Must be non-NULL.
 * @param[in] vmDirectoryLength The length of vmDirectory, in wchar_t.
 * @param[out] vmDirectoryEnd A pointer to the nul-terminator of the VM directory string. This cursor
 * can be used to append a string to the VM directory. Must be non-NULL.
 *
 * @return OMR_ERROR_NONE on success, an OMR error code otherwise.
 */
omr_error_t detectVMDirectory(wchar_t *vmDirectory, size_t vmDirectoryLength, wchar_t **vmDirectoryEnd);
#endif /* defined(OMR_OS_WINDOWS) */

#if defined(J9ZOS390)
/* ---------------- getstoragekey.c ---------------- */

/**
 * Get the storage key for current process on z/OS.
 *
 * @return The current z/OS storage protection key.
 *
 */

uintptr_t getStorageKey(void);

/* ---------------- zosversion.c ---------------- */

#define ZOS_V1R10_RELEASE 20.00
#define ZOS_V1R10_VERSION 3

#define ZOS_V2R4_RELEASE 27.00
#define ZOS_V2R4_VERSION 4

/**
 * Determine if the z/OS version is greater than or equal to a given
 * release and version. The implementation is based on uname(),
 * NOT on __osname() as the __osname() release numbers are not
 * guaranteed to increase.
 *
 * For release and version numbers, see
 * 	https://www.ibm.com/docs/en/zos/2.5.0?topic=functions-uname-display-current-operating-system-name
 *
 * @param[in] min_release the release to be checked.
 * @param[in] min_version the version to be checked.
 * @return TRUE if the z/OS version is greater than or equal to the given release and version,
 *         FALSE otherwise.
 */
BOOLEAN zos_version_at_least(double min_release, double min_version);
#endif /* defined(J9ZOS390) */

/**
 * Returns a string representing the type of page indicated by the given pageFlags.
 * Useful when printing page type.
 *
 * @param[in] pageFlags indicates type of the page.
 *
 * @return pointer to string representing the page type.
 */
const char *
getPageTypeString(uintptr_t pageFlags);

/**
 * Returns a string (with a leading space) representing the type of page indicated by the given pageFlags.
 * Useful when printing page type.
 *
 * @param[in] pageFlags indicates type of the page.
 *
 * @return pointer to string (with a leading space) representing the page type.
 */
const char *
getPageTypeStringWithLeadingSpace(uintptr_t pageFlags);


/* ---------------- j9memclr.c ---------------- */

/**
* @brief
* @param void
* @return uint32_t
*/
uint32_t getCacheLineSize(void);


/**
* @brief
* @param *ptr
* @param length
* @return void
*/
void OMRZeroMemory(void *ptr, uintptr_t length);


/**
* @brief
* @param *dest
* @param value
* @param size
* @return void
*/
void j9memset(void *dest, intptr_t value, uintptr_t size);

#if defined(J9ZOS39064)
/**
* @brief get maximum heap size allowed for zOS compressedrefs mode
* @return the heap size allowed
*/
U_64 zosGetMaxHeapSizeForCR(void);
#endif /* defined(J9ZOS39064) */

/* ---------------- wildcard.c ---------------- */

/**
* @brief
* @param pattern
* @param patternLength
* @param needle
* @param needleLength
* @param matchFlag
* @return IDATA
*/
IDATA
omrParseWildcard(const char * pattern, UDATA patternLength, const char** needle, UDATA* needleLength, U_32 * matchFlag);

/**
* @brief
* @param matchFlag
* @param needle
* @param needleLength
* @param haystack
* @param haystackLength
* @return IDATA
*/
IDATA
omrWildcardMatch(U_32 matchFlag, const char* needle, UDATA needleLength, const char* haystack, UDATA haystackLength);

/* ---------------- omrcrc32.c ---------------- */

/**
* @brief
* @param crc
* @param *bytes
* @param len
* @return U_32
*/
U_32 omrcrc32(U_32 crc, U_8 *bytes, U_32 len);

/**
* @brief
* @param crc
* @param *bytes
* @param len
* @param step
* @return U_32
*/
U_32 omrcrcSparse32(U_32 crc, U_8 *bytes, U_32 len, U_32 step);

/* ---------------- archinfo.c ---------------- */
/**
 * @brief
 * @return int32_t
 */

#define G5                              (9672)  /* Not Supported as of Java 1.5 */
#define MULTIPRISE7000                  (7060)  /* Not Supported as of Java 1.5 */
#define FREEWAY                         (2064)
#define Z800                            (2066)
#define MIRAGE                          (1090)
#define TREX                            (2084)
#define Z890                            (2086)
#define GOLDEN_EAGLE                    (2094)
#define DANU_GA2                        (2094)  /* type doesn't change from GOLDEN_EAGLE */
#define Z9BC                            (2096)
#define Z10                             (2097)
#define Z10BC                           (2098)  /* zMR */

int32_t get390zLinuxMachineType(void);

/* ---------------- poolForPort.c ---------------- */

#define POOL_FOR_PORT(portLib) (omrmemAlloc_fptr_t)pool_portLibAlloc, (omrmemFree_fptr_t)pool_portLibFree, (portLib)
#if defined(OMR_ENV_DATA64)
#define POOL_FOR_PORT_PUDDLE32(portLib) (omrmemAlloc_fptr_t)pool_portLibAlloc32, (omrmemFree_fptr_t)pool_portLibFree32, (portLib)
#else /* defined(OMR_ENV_DATA64) */
#define POOL_FOR_PORT_PUDDLE32(portLib) NULL, NULL, NULL
#endif /* defined(OMR_ENV_DATA64) */

void *
pool_portLibAlloc(OMRPortLibrary *portLibrary, uint32_t size, const char *callSite, uint32_t memoryCategory, uint32_t type, uint32_t *doInit);

void
pool_portLibFree(OMRPortLibrary *portLibrary, void *address, uint32_t type);

#if defined(OMR_ENV_DATA64)

void *
pool_portLibAlloc32(OMRPortLibrary *portLibrary, uint32_t size, const char *callSite, uint32_t memoryCategory, uint32_t type, uint32_t *doInit);

void
pool_portLibFree32(OMRPortLibrary *portLibrary, void *address, uint32_t type);
#endif /* defined(OMR_ENV_DATA64) */


/* ---------------- thrname_core.c ---------------- */

struct OMR_VMThread;

/**
 * Lock and get the thread name. Must be paired with releaseOMRVMThreadName().
 *
 * @param[in] vmThread The vmthread.
 * @return The thread name.
 */
char *getOMRVMThreadName(struct OMR_VMThread *vmThread);

/**
 * Try to lock and get the thread name. Fails if locking requires blocking.
 * If this call succeeds, it must be paired with releaseOMRVMThreadName().
 * Don't call releaseOMRVMThreadName() if this call failed.
 *
 * @param[in] vmThread The vmthread.
 * @return NULL if we failed to get the lock, a non-NULL thread name if we succeeded.
 */
char *tryGetOMRVMThreadName(struct OMR_VMThread *vmThread);

/**
 * Unlock the thread name that was obtained using getOMRVMThreadName() or tryGetOMRVMThreadName().
 * @param[in] vmThread The vmthread.
 */
void releaseOMRVMThreadName(struct OMR_VMThread *vmThread);

/**
 * Lock the thread name, set it, and then unlock it.
 * The thread name may be freed by the VM.
 *
 * @param[in] currentThread The current vmthread.
 * @param[in] vmThread The vmthread whose name should be set.
 * @param[in] name The new thread name.
 * @param[in] nameIsStatic If non-zero, this indicates that the VM should not free the thread name.
 */
void setOMRVMThreadNameWithFlag(struct OMR_VMThread *currentThread, struct OMR_VMThread *vmThread, char *name, uint8_t nameIsStatic);

/**
 * Set the thread name without locking it.
 *
 * @param[in] vmThread The vmthread whose name should be set.
 * @param[in] name The new thread name.
 * @param[in] nameIsStatic If non-zero, this indicates that the VM should not free the thread name.
 */
void setOMRVMThreadNameWithFlagNoLock(struct OMR_VMThread *vmThread, char *name, uint8_t nameIsStatic);

/* ---------------- threadhelp.c ---------------- */

/**
 * Helper function to create a thread with a specific thread category.
 *
 * @param[out] handle a pointer to a omrthread_t which will point to the thread (if successfully created)
 * @param[in] stacksize the size of the new thread's stack (bytes)<br>
 *			0 indicates use default size
 * @param[in] priority priorities range from J9THREAD_PRIORITY_MIN to J9THREAD_PRIORITY_MAX (inclusive)
 * @param[in] suspend set to non-zero to create the thread in a suspended state.
 * @param[in] entrypoint pointer to the function which the thread will run
 * @param[in] entryarg a value to pass to the entrypoint function
 * @param[in] category category of the thread to be created
 *
 * @return success or error code
 * @retval J9THREAD_SUCCESS success
 * @retval J9THREAD_ERR_xxx failure
 *
 * @see omrthread_create
 */
intptr_t
createThreadWithCategory(omrthread_t *handle, uintptr_t stacksize, uintptr_t priority, uintptr_t suspend,
	omrthread_entrypoint_t entrypoint, void *entryarg, uint32_t category);

/**
 * Helper function to attach a thread with a specific category.
 *
 * If the OS thread is already attached, handle is set to point to the existing omrthread_t.
 *
 * @param[out] handle a pointer to a omrthread_t which will point to the thread (if successfully attached)
 * @param[in]  category thread category
 *
 * @return success or error code
 * @retval J9THREAD_SUCCESS success
 * @retval J9THREAD_ERR_xxx failure
 *
 * @see omrthread_attach
 */
intptr_t
attachThreadWithCategory(omrthread_t *handle, uint32_t category);

/**
 * @brief
 * @param portLibrary
 * @param input
 * @return char *
 */
char * omr_trim(OMRPortLibrary *portLibrary, char * input);

/**
* @brief
* @param portLibrary
* @param module
* @param *scan_start
* @return void
*/
void omr_scan_failed(OMRPortLibrary *portLibrary, const char* module, const char *scan_start);

/**
* @brief
* @param portLibrary
* @param module
* @param *scan_start
* @return void
*/
void omr_scan_failed_incompatible(OMRPortLibrary *portLibrary, char* module, char *scan_start);

/**
* @brief
* @param portLibrary
* @param module
* @param *scan_start
* @return void
*/
void omr_scan_failed_unsupported(OMRPortLibrary *portLibrary, char* module, char *scan_start);

/**
* @brief
* @param **scan_start
* @param result
* @return uintptr_t
*/
uintptr_t omr_scan_hex(char **scan_start, uintptr_t* result);

/**
* @brief
* @param **scan_start
* @param uppercaseFalg
* @param result
* @return uintptr_t
*/
uintptr_t omr_scan_hex_caseflag(char **scan_start, BOOLEAN uppercaseAllowed, uintptr_t* result);

/**
* @brief
* @param **scan_start
* @param *result
* @return uintptr_t
*/
uintptr_t omr_scan_hex_u64(char **scan_start, uint64_t* result);

/**
* @brief
* @param **scan_start
* @param *result
* @return uintptr_t
*/
uintptr_t omr_scan_hex_caseflag_u64(char **scan_start, BOOLEAN uppercaseAllowed, uint64_t* result);

/**
* @brief
* @param **scan_start
* @param *result
* @return uintptr_t
*/
uintptr_t omr_scan_idata(char **scan_start, intptr_t *result);

/**
* @brief
* @param portLibrary
* @param **scan_start
* @param delimiter
* @return char *
*/
char *omr_scan_to_delim(OMRPortLibrary *portLibrary, char **scan_start, char delimiter);

/** 
 * Scan the next double number off of the argument string.
 * Store the scanned double value in *result
 *
 * @param[in/out] scan_start pointer to char * representing the string to be scanned,
                  on success, *scan_start is updated to point to the character after the last character converted to double
 * @param[out] result pointer to double, on success contains the scanned double value
 * @return on success returns OPTION_OK, on overflow returns OPTION_OVERFLOW,
 *         if no conversion is performed return OPTION_MALFORMED
 */
uintptr_t omr_scan_double(char **scan_start, double *result);

/**
* @brief
* @param **scan_start
* @param result
* @return uintptr_t
*/
uintptr_t omr_scan_udata(char **scan_start, uintptr_t* result);

/**
* @brief
* @param **scan_start
* @param result
* @return uintptr_t
*/
uintptr_t omr_scan_u64(char **scan_start, uint64_t* result);

/**
* @brief
* @param **scan_start
* @param result
* @return uint32_t
*/
uintptr_t omr_scan_u32(char **scan_start, uint32_t* result);

#ifdef __cplusplus
}
#endif

#endif /* OMRUTIL_H_INCLUDED */
