//
// include file with standard definitions missing in the libc from Android
//
// Please note that you must remove the definitions for functions that already exist in the source code from this include file.
// If not, error messages like this are displayed when compiling your source code:
//
//    command.c:(.text+0x348): multiple definition of `catclose'
//    array.o:array.c:(.text+0x348): first defined here
//
// Therefore, either edit this file before using it or copy only the necessary parts to your source files
//
//
// History
//  29.12.2024
//    initial release
//  22.01.2025 
//    added the function nl_langinfo
//  11.04.2025
//    added the functions getpwent and endpwent
//    the definitions for nl_langinfo and nl_catd now also can be used in C programs
//  13.04.2025
//    added the definition for CloseSocket
//  16.04.2025
//    added the definition for a replacement for the function mktime_z
//  16.06.2025 
//    added the definition for a replacement for the function bzero
//  07.07.2025
//    added the definition for isblank, min and max
//  03.10.2025
//    added the functions tzalloc, tzfree, localtime_rz, mktime_z for API < 35
//  18.12.2025
//    added the function android_getpass
//  03.01.2025
//    added the definition for PTR
//  03.02.2026
//    added the definition for bcmp
//  04.06.2026
//    added the function ldexpl
//    added the function frexpl
//
//
// This file defines
//   quad_t
//   u_quad_t
//   short
//   PTR
//
// This file defines the functions
//   strverscmp
//   versionsort
//   getdtablesize
//   index
//   rindex
//   catopen
//   catgets
//   catclose
//   nl_langinfo
//   getpwent
//   endpwent
//   CloseSocket
//   mktime_z
//   bzero
//   tzalloc
//   tzfree 
//   localtime_rz 
//   mktime_z
//   android_getpass
//   bcmp
//   ldexpl
//   frexpl
//
// This file defines the macros
//
//   __GNUC_PREREQ
//   isblank
//   min
//   max
//

#ifndef ADD_MISSING_DEFINITIONS_H

#define ADD_MISSING_DEFINITIONS_H

// --------------------------------------------------------------------
//
#ifndef __GNUC_PREREQ
#define __GNUC_PREREQ(maj, min) ((__GNUC__ > (maj)) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min)))
#endif


// --------------------------------------------------------------------
//
#ifndef quad_t

#include <stdint.h>

typedef int64_t quad_t;

#endif

// --------------------------------------------------------------------
//
#ifndef u_quad_t

#include <stdint.h>

typedef uint64_t u_quad_t;

#endif

// --------------------------------------------------------------------
//
#ifndef short

typedef unsigned short ushort;

#endif

// --------------------------------------------------------------------
//
#ifndef PTR
typedef void *PTR;
#endif

// --------------------------------------------------------------------
//
#ifndef strverscmp

#include <dirent.h>

int strverscmp(const char *l0, const char *r0)
{
	const unsigned char *l = (const void *)l0;
	const unsigned char *r = (const void *)r0;
	size_t i, dp, j;
	int z = 1;

	/* Find maximal matching prefix and track its maximal digit
	 * suffix and whether those digits are all zeros. */
	for (dp=i=0; l[i]==r[i]; i++) {
		int c = l[i];
		if (!c) return 0;
		if (!isdigit(c)) dp=i+1, z=1;
		else if (c!='0') z=0;
	}

	if (l[dp]!='0' && r[dp]!='0') {
		/* If we're not looking at a digit sequence that began
		 * with a zero, longest digit string is greater. */
		for (j=i; isdigit(l[j]); j++)
			if (!isdigit(r[j])) return 1;
		if (isdigit(r[j])) return -1;
	} else if (z && dp<i && (isdigit(l[i]) || isdigit(r[i]))) {
		/* Otherwise, if common prefix of digit sequence is
		 * all zeros, digits order less than non-digits. */
		return (unsigned char)(l[i]-'0') - (unsigned char)(r[i]-'0');
	}

	return l[i] - r[i];
}

#endif

// --------------------------------------------------------------------
//
#ifndef versionsort

static int versionsort(const struct dirent **a, const struct dirent **b)
{
	return strverscmp((*a)->d_name, (*b)->d_name);
}

#endif


// --------------------------------------------------------------------
//
#ifndef getdtablesize

#include <unistd.h>
#include <sys/resource.h>

int getdtablesize() {
    // Zuerst sysconf versuchen
    long max_fds = sysconf(_SC_OPEN_MAX);
    if (max_fds > 0) {
        return (int)max_fds;
    }

    // Fallback: getrlimit verwenden
    struct rlimit limit;
    if (getrlimit(RLIMIT_NOFILE, &limit) == 0) {
        return (int)limit.rlim_cur;
    }

    // Notlösung: Standardwert
    return 1024;
}

#endif

// --------------------------------------------------------------------
//
#ifndef index

#include <string.h>

char *index(const char *s, int c) {
    return strchr(s, c);
}

#endif

// --------------------------------------------------------------------
//
#ifndef rindex

#include <string.h>

char *rindex(const char *s, int c) {
    return strrchr(s, c);
}

#endif

// --------------------------------------------------------------------

#ifdef __ANDROID__
typedef void* nl_catd;


#ifndef __cplusplus
#define nullptr ((void*)0)
#endif


nl_catd catopen(const char *name, int flag) {
    return nullptr;
}

char* catgets(nl_catd catalog, int set_number, int message_number, const char *default_message) {
    return (char *)default_message;
}

int catclose(nl_catd catalog) {
    return 0;
}
#endif

// --------------------------------------------------------------------

#ifndef nl_langinfo

#ifndef CODESET
#define CODESET 0
#endif

const char* nl_langinfo(int item) {
    switch (item) {
        case CODESET:
            return "UTF-8";
        // Weitere Dummy-Werte, falls benötigt
        case 2: // Beispiel für ein anderes Element
            return "en_US";
        default:
            return "unknown"; // Fallback für nicht unterstützte Items
    }
}

#endif


// --------------------------------------------------------------------

#ifndef getpwent

#include <pwd.h>
#include <stddef.h>

// Dummy getpwent – always return NULL (no user)
struct passwd *getpwent(void) {
    return NULL;
}

#endif

// --------------------------------------------------------------------

#ifndef endpwent

#include <pwd.h>
#include <stddef.h>

// Dummy endpwent – do nothing
void endpwent(void) {
    // no-op
}

#endif

// --------------------------------------------------------------------

#ifndef CloseSocket
#define CloseSocket(x) close(x)
#endif

// --------------------------------------------------------------------

#ifndef mktime_z

time_t mktime_z(timezone_t tz, struct tm *tm) {
    return mktime(tm);  // Fallback without timezone
}

// If not using this function, replace mktime_z with mktime in the source code:

// Replace
//    time_t t = mktime_z(tz, &tm);

// With
//   time_t t = mktime(&tm);

#endif


// --------------------------------------------------------------------

#ifndef bzero

void bzero(void *s, size_t n) {
    memset(s, 0, n);
}

#endif


// --------------------------------------------------------------------

#ifndef isblank

#define isblank(c) ((c) == ' ' || (c) == '\t')

#endif

// --------------------------------------------------------------------

#ifndef min

#define min(a,b) ((a) < (b) ? (a) : (b))

#endif

#ifndef max

#define max(a,b) ((a) > (b) ? (a) : (b))

#endif

// --------------------------------------------------------------------

// these functions are defined in API 35 and newer only

#if !defined(__ANDROID__) || __ANDROID_API__ < 35

#include <time.h>
#include <stdlib.h>

void *tzalloc(const char *tz) {
    if (tz) setenv("TZ", tz, 1);
    tzset();
    return (void*)1; // Dummy TZ handle
}

void tzfree(void *tzobj) {
    (void)tzobj; // nichts tun
}

struct tm *localtime_rz(void *tz, const time_t *timep, struct tm *result) {
    (void)tz; // ignorieren, global TZ
    return localtime_r(timep, result);
}

time_t mktime_z(void *tz, struct tm *tm) {
    (void)tz; // ignorieren, global TZ
    return mktime(tm);
}

#endif


// --------------------------------------------------------------------

#if defined(__ANDROID__)
#include <termios.h>
#include <unistd.h>

static char *android_getpass(const char *prompt)
{
    static char buf[512];
    struct termios oldt, newt;

    if (prompt)
        write(STDOUT_FILENO, prompt, strlen(prompt));

    tcgetattr(STDIN_FILENO, &oldt);
    newt = oldt;
    newt.c_lflag &= ~ECHO;
    tcsetattr(STDIN_FILENO, TCSANOW, &newt);

    ssize_t len = read(STDIN_FILENO, buf, sizeof(buf) - 1);

    tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
    write(STDOUT_FILENO, "\n", 1);

    if (len > 0 && buf[len - 1] == '\n')
        buf[len - 1] = '\0';
    else
        buf[len] = '\0';

    return buf;
}

#define getpass android_getpass
#endif

// --------------------------------------------------------------------

#ifdef __ANDROID__
#define bcmp(a,b,n) memcmp((a),(b),(n))
#endif

// --------------------------------------------------------------------


#if defined(__ANDROID__)

#include <math.h>
#include <stdint.h>

/* 
 * frexpl - Zerlegt eine long double Zahl in Mantisse und Exponent
 * 
 * Parameter:
 *   x  - Die zu zerlegende Gleitkommazahl
 *   exp - Pointer auf int, der den Exponenten aufnehmen soll
 * 
 * Rückgabe:
 *   Die normalisierte Mantisse im Bereich [0.5, 1.0) oder 0.0
 *   Der Exponent wird in *exp gespeichert
 * 
 * Spezialfälle:
 *   - Bei x = 0:   Rückgabe 0, *exp = 0
 *   - Bei x = NaN: Rückgabe NaN, *exp = undefined
 *   - Bei x = Inf: Rückgabe Inf, *exp = undefined
 */
long double frexpl(long double x, int *exp) {
    union {
        long double ld;
        unsigned char bytes[sizeof(long double)];
    } u;
    
    /* Spezialfälle behandeln */
    if (x == 0.0L) {
        *exp = 0;
        return 0.0L;
    }
    
    if (isnan(x)) {
        *exp = 0;  /* undefiniert, aber wir setzen etwas */
        return x;
    }
    
    if (isinf(x)) {
        *exp = 0;  /* undefiniert, aber wir setzen etwas */
        return x;
    }
    
    /* 
     * Einfache iterative Implementierung für Android (Bionic)
     * Dies funktioniert für alle normalen Zahlen.
     * 
     * Für bessere Performance könnte man die Bit-Manipulation verwenden,
     * aber die ist aufgrund unterschiedlicher long double Formate
     * (80-bit extended precision vs. 128-bit IEEE quad) plattformabhängig.
     */
    long double mantissa = x;
    int exponent = 0;
    
    /* Normalisiere auf [0.5, 1.0) */
    if (mantissa != 0.0L) {
        while (mantissa >= 1.0L) {
            mantissa *= 0.5L;
            exponent++;
        }
        while (mantissa < 0.5L) {
            mantissa *= 2.0L;
            exponent--;
        }
    }
    
    *exp = exponent;
    return mantissa;
}
#endif


// --------------------------------------------------------------------

#if defined(__ANDROID__)

/*
 * ldexpl - Baut eine Gleitkommazahl aus Mantisse und Exponent
 * 
 * Parameter:
 *   x - Die Mantisse
 *   exp - Der Exponent (als Integer)
 * 
 * Rückgabe:
 *   x * 2^exp
 * 
 * Dies ist die Umkehrfunktion zu frexpl:
 *   ldexpl(frexpl(x, &exp), exp) == x (für normale Zahlen)
 */
long double ldexpl(long double x, int exp) {
    /* Spezialfälle */
    if (x == 0.0L || isnan(x) || isinf(x)) {
        return x;
    }
    
    /* Einfache iterative Multiplikation/Division mit 2 */
    long double result = x;
    
    if (exp > 0) {
        for (int i = 0; i < exp; i++) {
            result *= 2.0L;
        }
    } else if (exp < 0) {
        for (int i = 0; i < -exp; i++) {
            result *= 0.5L;
        }
    }
    
    return result;
}
#endif

// --------------------------------------------------------------------

#endif  /* ADD_MISSING_DEFINITIONS_H */

// --------------------------------------------------------------------
//


// --------------------------------------------------------------------







