#ifndef SML3__GUMMI_H_
#define SML3__GUMMI_H_

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

  Gummistrings sind normale C-Strings, deren Allokation anwachsen kann.
  Zuerst wird ein Gummistring mit SML3_guminit() oder SML3_GUM_INITIALIZER
  initialisiert.
  Danach koennen in ihn Strings mit den verschiedenen Funktionen gesetzt
  werden:
   - SML3_gumcpy()      verhaelt sich wie str(l)cpy
   - SML3_gumncpy()     verhaelt sich wie strncpy
   - SML3_gumset()      verhaelt sich wie memset
   - SML3_gummove()     verhaelt sich wie memmove
   - SML3_gumprintf()   verhaelt sich wie sprintf
   - SML3_gumvprintf()  verhaelt sich wie vsprintf
   - SML3_gumalloc()    erweitert die Allokation
   - SML3_gumsize()     gibt die aktuelle Allokationsgroesse zurueck
   - SML3_gumswapgum()  vertauscht die Werte zweier Gummistrings
   - SML3_gumswapstr()  vertauscht den Gummistring-Wert mit dem uebergebenen String
   - SML3_gumgetval()   gibt den Pointer auf den Inhalt zurueck
   - SML3_gumfget()     liest Datei zeilenweise in den Gummistring
   - SML3_gumsget()     liest String zeilenweise in den Gummistring
  Mit SML3_gumdest() wird der Gummistring freigegeben
+++ */


/* ++++++++++++++++
 * +++ Beispiel +++
 * ++++++++++++++++

  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <sys/types.h>
  #include <unistd.h>
  #include <errno.h>
  #include <sammel3.h>

  int main(void) {
    struct SML3_gummi gm1 = SML3_GUM_INITIALIZER;
    struct SML3_gummi gm2 = SML3_GUM_INITIALIZER;
    char *ptr;

    // beide Gummistrings setzen
    SML3_gumcpy(&gm1, 0, "Das ist Gummi 1");
    SML3_gumprintf(&gm2, 0, "Das ist Gummi %d", 2);

    // beide Gummistrings ausgeben
    printf("Gummi1: \"%s\"\n", SML3_gumgetval(&gm1));
    printf("Gummi2: \"%s\"\n", SML3_gumgetval(&gm2));

    // beide Gummistrings vertauschen
    printf("Vertausche Gummistrings\n");
    SML3_gumswapgum(&gm1, &gm2);

    // beide Gummistrings ausgeben
    printf("Gummi1: \"%s\"\n", SML3_gumgetval(&gm1));
    printf("Gummi2: \"%s\"\n", SML3_gumgetval(&gm2));

    // bei beiden Gummistrings Werte austauschen
    printf("Tausche Gummistring-Werte aus\n");
    ptr = SML3_gumswapstr(&gm1, strdup("G1"), 0);
    printf("Gummi1: Alt=\"%s\", Neu=\"%s\"\n", ptr, SML3_gumgetval(&gm1));
    free(ptr);
    ptr = SML3_gumswapstr(&gm2, NULL, 0);
    printf("Gummi2: Alt=\"%s\", Neu=\"%s\"\n", ptr, SML3_gumgetval(&gm2));
    free(ptr);

    // aufraeumen
    SML3_gumdest(&gm1);
    SML3_gumdest(&gm2);

    exit(0);
  }
+++ */


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

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

struct SML3_gummi {  /* Gummistring */
  char *val;        /* Gummistring-Wert */
  size_t allo;      /* Allokationsgroesse */
};

/* Initialisierer fuer Gummistring:  struct SML3_gummi gm = SML3_GUM_INITIALIZER; */
#define SML3_GUM_INITIALIZER  { NULL, 0 }


/** SML3_guminit [thread-sicher]:
 * initialisiert Gummistring;
 * muss einmalig vor Verwendung des Gummistrings aufgerufen werden,
 * alternativ kann SML3_GUM_INITIALIZER verwendet werden
 * 1.Arg: Adresse eines Gummistrings
 * 2.Arg: Initial-Allokationsgroesse
 */
extern void SML3_guminit(struct SML3_gummi *, size_t);


/** SML3_gumdest [thread-sicher]:
 * gibt Gummistring-Speicher frei;
 * vor einer weiteren Verwendung des Gummistrings
 * ist zuvor SML3_guminit() aufzurufen
 * 1.Arg: Adresse des Gummistrings
 */
extern void SML3_gumdest(struct SML3_gummi *);


/** SML3_gumgetval [thread-sicher]:
 * gibt den Pointer auf den Gummistring-Wert Inhalt zurueck
 * (er kann ungueltig werden, wenn der Gummistring veraendert wird)
 * 1.Arg: Adresse des Gummistrings
 * Rueckgabe: Pointer auf Gummistring-Wert (oder leer)
 */
extern char * SML3_gumgetval(struct SML3_gummi *);


/** SML3_gumalloc [thread-sicher]:
 * alloziert Gummistring-Wert auf Laenge 2.Arg
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval())
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: zu allozierende Groesse
 * Rueckgabe: Pointer auf Gummistring-Wert
 */
extern char * SML3_gumalloc(struct SML3_gummi *, size_t);


/** SML3_gumsize [reentrant]:
 * gibt Allokationsgroesse des Gummistring-Wertes zurueck
 * 1.Arg: Adresse des Gummistrings
 * Rueckgabe: Allokationsgroesse des Gummistring-Wertes
 */
extern size_t SML3_gumsize(struct SML3_gummi *);


/** SML3_gumswapgum [thread-sicher]:
 * vertauscht die Werte zweier Gummistrings
 * 1.+2.Arg: zu tauschende Gummistrings
 */
extern void SML3_gumswapgum(struct SML3_gummi *, struct SML3_gummi *);


/** SML3_gumswapstr [thread-sicher]:
 * vertauscht den Gummistring-Wert 1.Arg mit dem uebergebenen String 2.Arg
 * und gibt Pointer auf alten Gummistring-Wert zurueck;
 * veraendert Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * Der neue Gummistring-Wert ist das 2.Arg, keine Kopie,
 * daher muss das 2.Arg dynamisch alloziert sein.
 * Der Rueckgabewert muss freigegeben werden.
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: neuer zu setzender Wert oder NULL
 * 3.Arg: Allokationsgroesse 2.Arg oder 0 = Stringlaenge + 1
 * Rueckgabe: (freizugebenden) Pointer auf alten Gummistring-Wert
 *
 * Falls der neue Wert (2.Arg) NULL ist, kann danach SML3_gumdest() und/oder
 * SML3_guminit() aufgerufen werden, muss aber nicht
 */
extern char * SML3_gumswapstr(struct SML3_gummi *, char *, size_t);


/** SML3_gumcpy [thread-sicher]:
 * aehnlich str(l)cpy fuer Gummistrings
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: Position, ab der kopiert werden soll
 * 3.Arg: zu kopierender String
 * Rueckgabe: Anzahl kopierter Zeichen
 */
extern size_t SML3_gumcpy(struct SML3_gummi *, size_t, const char *);


/** SML3_gumncpy [thread-sicher]:
 * wie strncpy fuer Gummistrings
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: Position, ab der kopiert werden soll
 * 3.Arg: zu kopierender String
 * 4.Arg: Anzahl zu kopierender Zeichen
 * Rueckgabe: Pointer auf Gummistring-Wert
 */
extern char * SML3_gumncpy(struct SML3_gummi *, size_t, const char *, size_t);


/** SML3_gumset [thread-sicher]:
 * wie memset fuer Gummistrings
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: Position, ab der Zeichen gesetzt werden sollen
 * 3.Arg: zu setzendes Zeichen
 * 4.Arg: Anzahl zu setzender Zeichen
 * Rueckgabe: Pointer auf Gummistring-Wert
 */
extern char * SML3_gumset(struct SML3_gummi *, size_t, int, size_t);


/** SML3_gummove [thread-sicher]:
 * wie memmove fuer Gummistrings
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: Position, ab der kopiert werden soll
 * 3.Arg: zu kopierender Bereich
 * 4.Arg: Anzahl zu kopierender Zeichen
 * Rueckgabe: Pointer auf Gummistring-Wert
 */
extern char * SML3_gummove(struct SML3_gummi *, size_t, const char *, size_t);


/** SML3_gumprintf [thread-sicher]:
 * wie sprintf fuer Gummistrings
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: Position, ab der kopiert werden soll
 * 3.Arg: Formatstring
 * weitere Arg: Variablen fuer Formatstring
 * Rueckgabe: Anzahl kopierter Zeichen
 */
extern int SML3_gumprintf(struct SML3_gummi *, size_t, const char *, ...);


/** SML3_gumvprintf [thread-sicher]:
 * wie vsprintf fuer Gummistrings
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: Position, ab der kopiert werden soll
 * 3.Arg: Formatstring
 * 4.Arg: mit va_start() ermittelte Argumentliste
 *        (es wird kein va_end() aufgerufen)
 * Rueckgabe: Anzahl kopierter Zeichen
 */
extern int SML3_gumvprintf(struct SML3_gummi *, size_t, const char *, va_list);


/** SML3_gumfget [thread-sicher]:
 * aehnlich fgets, aber Rueckgabe in Gummistring
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: Position, ab der kopiert werden soll
 * 3.Arg: Filepointer, aus dem gelesen wird
 * Rueckgabe: >0 = Anzahl gelesener Zeichen
 *             0 = Dateiende
 *            -1 = Fehler
 * SML3-errno-Wert: EIO = Fehler Lesen aus Filepointer
 */
extern ssize_t SML3_gumfget(struct SML3_gummi *, size_t, FILE *);


/** SML3_gumsget [thread-sicher]:
 * wie SML3_gumfget, liest aber aus einem String statt einer Datei
 * veraendert evtl. Gummistring-Wert-Adresse (siehe SML3_gumgetval()).
 * 1.Arg: Adresse des Gummistrings
 * 2.Arg: Position, ab der kopiert werden soll
 * 3.Arg: Adresse auf Stringpointer, ab wo gelesen werden soll
 *        Achtung: Aendert sich mit jedem Aufruf.
 * Rueckgabe: >0 = Anzahl gelesener Zeichen
 *             0 = Stringende
 */
extern ssize_t SML3_gumsget(struct SML3_gummi *, size_t, char **);

#endif /* SML3__GUMMI_H_ */
