#ifndef SML3__UTIL_H
#define SML3__UTIL_H

/* ++++++++++++++++++++
 * +++ Beschreibung +++
 * ++++++++++++++++++++

 Enthaelt verschiedene Funktionen
+++ */


/* ++++++++++++++++++ */
/* +++ Funktionen +++ */
/* ++++++++++++++++++ */

#include <stdio.h>
#include <string.h>
#include <sys/types.h>

/* allgemeine Struktur fuer Datenpointer mit Anzahl */
struct SML3_datum {
  char *dptr;    /* Daten */
  size_t dsize;  /* Anzahl Zeichen in dptr */
};


/** Zahlen-Wert setzen in und erhalten aus einem Memory-Bereich, vermeidet Zugriff auf unaligned Adressen
 * 1.Arg: Start-Pointer im Memory-Bereich
 * 2.Arg: Zahlen-Variable (short, int, SML3_int64)
 * - SML3_UTIL_SETMEM_*: Zahlen-Wert setzen
 * - SML3_UTIL_GETMEM_*: Zahlen-Wert erhalten
 * - SML3_UTIL_SETMEM_NW*: Zahlen-Wert konvertiert von Host- zu Netzwerk-Byte-Order setzen
 * - SML3_UTIL_GETMEM_NW*: Zahlen-Wert konvertiert von Netzwerk- zu Host-Byte-Order erhalten
 * Bsp:
 *   char c[4];
 *   short s;
 *   s = 258; SML3_UTIL_SETMEM_SHORT(c + 1, s);  // setzen
 *   SML3_UTIL_GETMEM_SHORT(c + 1, s); printf("%hd\n", s);  // erhalten
 */
#define SML3_UTIL_GETMEM_SHORT(P1, P2) { union { char c[2]; short i; } _u; _u.c[0] = (P1)[0]; _u.c[1] = (P1)[1]; (P2) = _u.i; }
#define SML3_UTIL_SETMEM_SHORT(P1, P2) { union { char c[2]; short i; } _u; _u.i = (P2); (P1)[0] = _u.c[0]; (P1)[1] = _u.c[1]; }
#define SML3_UTIL_GETMEM_INT(P1, P2) { union { char c[4]; int i; } _u; memmove(_u.c, (P1), 4); (P2) = _u.i; }
#define SML3_UTIL_SETMEM_INT(P1, P2) { union { char c[4]; int i; } _u; _u.i = (P2); memmove((P1), _u.c, 4); }
#define SML3_UTIL_GETMEM_INT64(P1, P2) { union { char c[8]; SML3_int64 i; } _u; memmove(_u.c, (P1), 8); (P2) = _u.i; }
#define SML3_UTIL_SETMEM_INT64(P1, P2) { union { char c[8]; SML3_int64 i; } _u; _u.i = (P2); memmove((P1), _u.c, 8); }

#define SML3_UTIL_GETMEM_NWSHORT(P1, P2) { union { char c[2]; short i; } _u; _u.c[0] = (P1)[0]; _u.c[1] = (P1)[1]; (P2) = SML3_ntoh16(_u.i); }
#define SML3_UTIL_SETMEM_NWSHORT(P1, P2) { union { char c[2]; short i; } _u; _u.i = SML3_hton16(P2); (P1)[0] = _u.c[0]; (P1)[1] = _u.c[1]; }
#define SML3_UTIL_GETMEM_NWINT(P1, P2) { union { char c[4]; int i; } _u; memmove(_u.c, (P1), 4); (P2) = SML3_ntoh32(_u.i); }
#define SML3_UTIL_SETMEM_NWINT(P1, P2) { union { char c[4]; int i; } _u; _u.i = SML3_hton32(P2); memmove((P1), _u.c, 4); }
#define SML3_UTIL_GETMEM_NWINT64(P1, P2) { union { char c[8]; SML3_int64 i; } _u; memmove(_u.c, (P1), 8); (P2) = SML3_ntoh64(_u.i); }
#define SML3_UTIL_SETMEM_NWINT64(P1, P2) { union { char c[8]; SML3_int64 i; } _u; _u.i = SML3_hton64(P2); memmove((P1), _u.c, 8); }


/** SML3_malloc [thread-sicher]:
 * wie malloc(), beendet sich aber bei Fehler
 * Args: wie bei malloc()
 * Rueckgabe: Pointer auf Memory
 */
extern void * SML3_malloc(size_t);


/** SML3_calloc [thread-sicher]:
 * wie calloc(), beendet sich aber bei Fehler
 * Args: wie bei calloc()
 * Rueckgabe: Pointer auf Memory
 */
extern void * SML3_calloc(size_t, size_t);


/** SML3_realloc [thread-sicher]:
 * realloc(), beendet sich aber bei Fehler
 * Args: wie bei realloc()
 * Rueckgabe: Pointer auf Memory
 */
extern void * SML3_realloc(void *, size_t);


/** SML3_strdup [thread-sicher]:
 * wie strdup(), beendet sich aber bei Fehler
 * Args: wie bei strdup()
 * Rueckgabe: Pointer auf Memory
 */
extern char * SML3_strdup(const char *);


/** SML3_memdup [thread-sicher]:
 * gibt allozierten Bereich mit kopierten Daten zurueck
 * 1.Arg: zu kopierende Daten
 * 2.Arg: Anzahl zu kopierender Daten
 * Rueckgabe: Pointer auf Memory oder NULL, wenn Argumente ungueltig
 */
extern void * SML3_memdup(const char *, size_t);


/** SML3_errno_is_eagain [reentrant]:
 * prueft, ob 1.Arg EAGAIN oder, falls definiert, EWOULDBLOCK ist
 * 1.Arg: errno-Wert
 * Rueckgabe: 1 = ja, 0 = nein
 */
extern int SML3_errno_is_eagain(int);


/** SML3_toupper [reentrant]:
 * wie toupper() fuer einen String in der C-Lokale
 * (siehe auch SML3_latin_toupper())
 * 1.Arg: String, wird veraendert
 * 2.Arg: Anzahl zu veraendernde Bytes im 1.Arg, oder 0 = bis Ende-0
 * Rueckgabe: 1.Arg
 */
extern char * SML3_toupper(char *, size_t);


/** SML3_tolower [reentrant]:
 * wie tolower() fuer einen String in der C-Lokale
 * (siehe auch SML3_latin_tolower())
 * 1.Arg: String, wird veraendert
 * 2.Arg: Anzahl zu veraendernde Bytes im 1.Arg, oder 0 = bis Ende-0
 * Rueckgabe: 1.Arg
 */
extern char * SML3_tolower(char *, size_t);


/** SML3_primzahl [thread-sicher]:
 * Ermittelt naechstgelegene Primzahl von 1.Arg
 * 1.Arg: Zahl, ab der die Primzahl ermittelt wird
 * 2.Arg: -1=abwaerts ermitteln
 *         1=aufwaerts ermitteln
 * Rueckgabe: ermittelte Primzahl
 */
extern unsigned long SML3_primzahl(unsigned long, int);


/** SML3_hton16 [reentrant]:
 * konvertiert unsigned short von Host-Byte-Order zu Netzwerk-Byte-Order
 * 1.Arg: Wert in Host-Byte-Order
 * Rueckgabe: Wert in Netzwerk-Byte-Order
 */
extern unsigned short SML3_hton16(unsigned short);


/** SML3_ntoh16 [reentrant]:
 * konvertiert unsigned short von Netzwerk-Byte-Order zu Host-Byte-Order
 * 1.Arg: Wert in Netzwerk-Byte-Order
 * Rueckgabe: Wert in Host-Byte-Order
 */
extern unsigned short SML3_ntoh16(unsigned short);


/* SML3_hton32 [reentrant]:
 * konvertiert unsigned int von Host-Byte-Order zu Netzwerk-Byte-Order
 * 1.Arg: Wert in Host-Byte-Order
 * Rueckgabe: Wert in Netzwerk-Byte-Order
 */
extern unsigned int SML3_hton32(unsigned int);


/* SML3_ntoh32 [reentrant]:
 * konvertiert unsigned int von Netzwerk-Byte-Order zu Host-Byte-Order
 * 1.Arg: Wert in Netzwerk-Byte-Order
 * Rueckgabe: Wert in Host-Byte-Order
 */
extern unsigned int SML3_ntoh32(unsigned int);


/* SML3_hton64 [reentrant]:
 * konvertiert unsigned SML3_int64 von Host-Byte-Order zu Netzwerk-Byte-Order
 * 1.Arg: Wert in Host-Byte-Order
 * Rueckgabe: Wert in Netzwerk-Byte-Order
 */
extern unsigned SML3_int64 SML3_hton64(unsigned SML3_int64);


/* SML3_ntoh64 [reentrant]:
 * konvertiert unsigned SML3_int64 von Netzwerk-Byte-Order zu Host-Byte-Order
 * 1.Arg: Wert in Netzwerk-Byte-Order
 * Rueckgabe: Wert in Host-Byte-Order
 */
extern unsigned SML3_int64 SML3_ntoh64(unsigned SML3_int64);


/** SML3_zufallzahl [thread-sicher]:
 * gibt eine zufaellige Zahl zwischen 1.Arg und 2.Arg zurueck
 * 1.Arg: Startwert (inkl.)
 * 2.Arg: Endewert (inkl.)
 * Rueckgabe: zufaellige Zahl (oder 0, wenn 1.Arg > 2.Arg)
 */
extern int SML3_zufallzahl(int, int);


/** SML3_schnipp [thread-sicher]:
 * schneidet im 1.Arg vorne oder/und hinten eine Auswahl von Zeichen ab
 * 1.Arg: zu stutzender String
 * 2.Arg: Auswahl von Zeichen
 * 3.Arg: 1 = vorne, 2 = hinten, 3 = vorne + hinten
 * Rueckgabe: Byteanzahl des gestutzten Strings
 */
extern size_t SML3_schnipp(char *, const char *, int);


/** SML3_memmem [thread-sicher]:
 * sucht 3.Arg im 1.Arg und gibt erstes Vorkommen zurueck
 * 1.+2.Arg: zu durchsuchender String mit Stringlaenge
 * 3.+4.Arg: zu suchender String mit Stringlaenge
 * 5.Arg: ob Gross-/Klein-Schreibung (nur ASCII) egal: 0 = nein, 1 = ja
 * Rueckgabe: Pointer auf erstes Vorkommen oder NULL = nicht gefunden
 *
 * Bsp fuer Ausgabe aller Vorkommen von needle in haystack:
 *   const char *p1 = haystack;
 *   const char *p2 = needle;
 *   char *rptr;
 *   while ((rptr = SML3_memmem(p1, strlen(p1), p2, strlen(p2), 0)) != NULL) {
 *     printf("- %s\n", rptr);
 *     p1 = rptr + strlen(p2);
 *   }
 */
extern void * SML3_memmem(const void *, size_t, const void *, size_t, int);


/** SML3_antoi [thread-sicher]:
 * ermittelt (signed) Zahl aus String
 * 1.Arg: String
 * 2.Arg: maximale auszwertende Laenge oder 0 = ohne Begrenzung
 * Rueckgabe: Zahl
 */
extern SML3_int64 SML3_antoi(const char *, size_t);


/** SML3_antoui [thread-sicher]:
 * ermittelt (unsigned) Zahl aus String
 * 1.Arg: String
 * 2.Arg: maximale auszwertende Laenge oder 0 = ohne Begrenzung
 * Rueckgabe: Zahl
 */
extern unsigned SML3_int64 SML3_antoui(const char *, size_t);


/** SML3_antof [thread-sicher]:
 * ermittelt double-Zahl aus String
 * 1.Arg: String
 * 2.Arg: maximale auszwertende Laenge oder 0 = ohne Begrenzung
 * Rueckgabe: Zahl
 */
extern double SML3_antof(const char *, size_t);


/** SML3_strtoi [thread-sicher]:
 * ermittelt (signed) Zahl aus String, aehnlich strtol()
 * 1.Arg: String
 * 2.Arg: maximale auszwertende Laenge oder 0 = ohne Begrenzung
 * 3.Arg: fuer Rueckgabe Pointer auf erstes ungueltiges Zeichen
 *        oder NULL
 * 4.Arg: Basis (2 bis 36)
 * Rueckgabe: Zahl
 */
extern SML3_int64 SML3_strtoi(const char *, size_t, char **, int);


/** SML3_strtoui [thread-sicher]:
 * ermittelt (unsigned) Zahl aus String, aehnlich strtoul()
 * 1.Arg: String
 * 2.Arg: maximale auszwertende Laenge oder 0 = ohne Begrenzung
 * 3.Arg: fuer Rueckgabe Pointer auf erstes ungueltiges Zeichen
 *        oder NULL
 * 4.Arg: Basis (2 bis 36)
 * Rueckgabe: Zahl
 */
extern unsigned SML3_int64 SML3_strtoui(const char *, size_t, char **, int);


/** SML3_uitostr [thread-sicher]:
 * gibt Zahl 1.Arg als String mit Basis 2.Arg zurueck
 * 1.Arg: Zahl
 * 2.Arg: Basis (2 bis 36)
 * 3.+4.Arg: Puffer mit Size fuer Rueckgabestring
 *           oder NULL = Rueckgabe ist alloziert
 * Rueckgabe: Pointer auf 3.Arg bzw. auf allozierten String
 *            oder NULL = Fehler
 * SML3-errno-Wert: ENOSPC = 4.Arg ist zu klein
 */
extern char * SML3_uitostr(unsigned SML3_int64, int, char *, size_t);


/** SML3_zeitpunkt_diff [thread-sicher]:
 * Ermittelt Zeitpunkt-Differenz
 * 1.Arg: Adresse auf: letzter Zeitpunkt oder Wert=0: setze Startzeitpunkt
 *        Rueckgabe: aktualisierter Zeitpunkt
 * Rueckgabe: Zeitpunkt-Differenz in Millisekunden
 *            (ist absoluter Zeitwert, wenn Wert 1.Arg = 0 bzw. 1.Arg = NULL)
 */
extern SML3_int64 SML3_zeitpunkt_diff(SML3_int64 *);


/** SML3_sleep_msek [thread-sicher]:
 * schlaeft 1.Arg Millisekunden
 * 1.Arg: zu schlafende Millisekunden
 */
extern void SML3_sleep_msek(int);


/** SML3_getlock [thread-sicher]:
 * (Ent)Sperrt Datei(bereich). Vorsicht bei NFS!
 * 1.Arg: Dateideskriptor der zu (ent)sperrenden Datei
 * 2.Arg: absolute Startposition des zu (ent)sperrenden Bereichs
 * 3.Arg: Anzahl der zu (ent)sperrenden Bytes
 *        oder 0 = bis EOF (ungut, wenn Dateilaenge sich veraendert!)
 * 4.Arg: Adresse fuer PID des sperrenden Prozesses oder NULL
 * 5.Arg: 0 = entsperren, 1 = sperren, 2 = blockiert sperren
 * Rueckgabe: 1 = OK
 *            0 = Lock nicht erhalten bzw. Fehler
 * SML3-errno-Wert: ENOENT = Fehler bei fcntl()
 *                  ENOLCK = nicht-blockierenden Lock nicht erhalten, 4.Arg ist gesetzt
 */
extern int SML3_getlock(int, unsigned long, unsigned long, pid_t *, int);


/** SML3_tmpfile [thread-sicher]:
 * wie tmpfile(), aber mit Angabe des Verzeichnisses
 * 1.Arg: Verzeichnis der temporaeren Datei (oder NULL = "/tmp")
 * 2.Arg: Zusatz fuer Dateinamen oder NULL
 * Rueckgabe: Filepointer oder NULL = Fehler
 * SML3-errno-Wert: EINVAL = Fehler Dateierstellung
 */
extern FILE * SML3_tmpfile(const char *, const char *);

#endif /* SML3__UTIL_H */
