#ifndef SML3__LATIN_H_
#define SML3__LATIN_H_

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

  Funktionen fuer Konvertierung von Zeichen von und nach ISO, ASCII, UTF-8.
  SML3_latin_isutf8() gibt zurueck, ob ein String UTF-8 kodiert ist,
  SML3_latin_next() gibt naechstes Zeichen konvertiert zurueck,
  SML3_latin_convert() konvertiert einen String.

  Die IO-Flags geben die Konvertierungsart an:
  - SML3_LATIN_INPUT_* gibt den Input-Zeichensatz an (es kann nicht kombiniert werden)
    - SML3_LATIN_INPUT_ISO:  ISO-8859-1(5)
    - SML3_LATIN_INPUT_UTF8: UTF-8
  - SML3_LATIN_OUTPUT_* gibt den Output-Zeichensatz an (es kann nicht kombiniert werden)
    wobei ein Eingabezeichen zu mehreren Zeichen bzw. Worten konvertiert
    werden kann
    - SML3_LATIN_OUTPUT_ASCII:   ASCII - geeignet fuer Indexierung
    - SML3_LATIN_OUTPUT_SORT:    ASCII - geeignet fuer Stringsortierung
    - SML3_LATIN_OUTPUT_ISO:     ISO-8859-1
    - SML3_LATIN_OUTPUT_UTF8:    UTF-8
    - SML3_LATIN_OUTPUT_UPCASE:  Kleinbuchstaben gross machen
    - SML3_LATIN_OUTPUT_LWCASE:  Grossbuchstaben klein machen
  - SML3_LATIN_MODIF_* gibt Zusatzparameter fuer die Konvertierung an
    - SML3_LATIN_MODIF_UML: deutsche Umlaute werden mit Zusatz-E anstelle
                           des Grundbuchstaben konvertiert (AE statt A),
                           wird ignoriert bei SML3_LATIN_OUTPUT_UTF8
                           und SML3_LATIN_OUTPUT_UPCASE und SML3_LATIN_OUTPUT_LWCASE
+++ */


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

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

  // zeichenweise Konvertierung
  void konv1(const char *string, size_t stringlen, int ioflag) {
    int eanz;
    char rzch[32];
    size_t rsize;

    if (string == NULL || stringlen == 0) { return; }

    rsize = sizeof(rzch);  // fuer Rueckgabe konvertiertes Zeichen
    while ((eanz = SML3_latin_next(ioflag, string, stringlen, rzch, &rsize)) > 0) {
      fwrite(rzch, 1, rsize, stdout);
      string += eanz;
      stringlen -= eanz;
      rsize = sizeof(rzch);
    }
    if (eanz < 0) {  // nicht konvertierter Rest in string+stringlen
      fwrite("[", 1, 1, stdout);
      fwrite(string, 1, stringlen, stdout);
      fwrite("]", 1, 1, stdout);
    }
  }

  // String-Konvertierung
  void konv2(const char *string, size_t stringlen, int ioflag) {
    struct SML3_gummi gm = SML3_GUM_INITIALIZER;
    size_t glen, slen;

    if (string == NULL || stringlen == 0) { return; }

    slen = stringlen;
    glen = SML3_latin_convert(ioflag, string, &slen, &gm, 0);
    fwrite(SML3_gumgetval(&gm), 1, glen, stdout);
    SML3_gumdest(&gm);

    if (slen > 0) {  // nicht konvertierter Rest in string+stringlen-slen
      fwrite("[", 1, 1, stdout);
      fwrite(string + stringlen - slen, 1, slen, stdout);
      fwrite("]", 1, 1, stdout);
    }
  }

  int main(int argc, char **argv) {
    int iflag, oflag;
    char *string;
    size_t stringlen;

    if (argc < 2) { exit(1); }

    string = argv[1];  // zu konvertierender String
    stringlen = strlen(string);

    // pruefen, ob String UTF-8 kodiert ist
    if (SML3_latin_isutf8(string, stringlen)) {  // ja
      iflag = SML3_LATIN_INPUT_UTF8;
      oflag = SML3_LATIN_OUTPUT_ISO;
    } else {  // nein
      iflag = SML3_LATIN_INPUT_ISO;
      oflag = SML3_LATIN_OUTPUT_UTF8;
    }

    // zeichenweise Konvertierung von ISO nach UTF-8 bzw. umgekehrt
    konv1(string, stringlen, iflag | oflag);
    printf("\n");

    // String-Konvertierung von ISO nach UTF-8 bzw. umgekehrt
    konv2(string, stringlen, iflag | oflag);
    printf("\n");

    // alle lateinischen Zeichen gross ausgeben
    konv2(string, stringlen, iflag | SML3_LATIN_OUTPUT_UPCASE);
    printf("\n");

    // alternativ: alle lateinischen Zeichen gross ausgeben
    { char *ptr = SML3_latin_toupper((iflag == SML3_LATIN_INPUT_UTF8), string);
      printf("%s\n", ptr);
      free(ptr);
    }

    exit(0);
  }

+++ */


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

#include <sys/types.h>

#define SML3_LATIN_INPUT_ISO            1
#define SML3_LATIN_INPUT_UTF8           2
#define SML3_LATIN_OUTPUT_ASCII        16
#define SML3_LATIN_OUTPUT_SORT         32
#define SML3_LATIN_OUTPUT_ISO          64
#define SML3_LATIN_OUTPUT_UTF8        128
#define SML3_LATIN_OUTPUT_UPCASE      256
#define SML3_LATIN_OUTPUT_LWCASE      512
#define SML3_LATIN_MODIF_UML      1048576
#define SML3_LATIN_INPUTMASK      (1|2)
#define SML3_LATIN_OUTPUTMASK     (16|32|64|128|256|512)
#define SML3_LATIN_MODIFMASK      (1048576)


/** SML3_latin_isutf8 [reentrant]:
 * gibt zurueck, ob String UTF-8 kodiert ist
 * 1.Arg: String
 * 2.Arg: Stringlaenge
 * Rueckgabe: 1 = UTF-8 kodiert
 *            0 = nicht UTF-8 kodiert
 */
extern int SML3_latin_isutf8(const char *, size_t);


/** SML3_latin_index [thread-sicher]:
 * gibt Zeichen gemaess Indexzahl zurueck
 * 1.Arg: IO-Flag
 *        - eins aus SML3_LATIN_OUTPUT_*
 *          (falls SML3_LATIN_OUTPUT_{UP|LW}CASE und 2.Arg im ISO-Zeichensatz,
 *           muss SML3_LATIN_INPUT_ISO angegeben werden
 *           fuer Rueckgabe im ISO-Zeichensatz)
 *        - evtl. aus SML3_LATIN_MODIF_*
 * 2.Arg: Indexzahl
 * 3.Arg: fuer Rueckgabe Zeichenstring (ohne Ende-0)
 * 4.Arg: Uebergabe=sizeof(3.Arg), Rueckgabe=Anzahl Bytes im 3.Arg
 * Rueckgabe: 1 = OK oder 0 = Indexzahl ungueltig
 */
extern int SML3_latin_index(int, int, char *, size_t *);


/** SML3_latin_next [thread-sicher]:
 * gibt naechstes Zeichen zurueck
 * 1.Arg: IO-Flag
 *        - eins aus SML3_LATIN_INPUT_*
 *          (wenn fehlt, wird UTF-8 verwendet, und eventuelle ISO-Zeichen akzeptiert)
 *        - eins aus SML3_LATIN_OUTPUT_*
 *        - evtl. aus SML3_LATIN_MODIF_*
 * 2.Arg: String
 * 3.Arg: Stringlaenge
 * 4.Arg: fuer Rueckgabe Zeichenstring (ohne Ende-0)
 * 5.Arg: Uebergabe=sizeof(4.Arg), Rueckgabe=Anzahl Bytes im 4.Arg
 * Rueckgabe: Anzahl verwendeter Bytes im String
 *            oder 0  = Ende
 *            oder -1 = ungueltiges Byte bzw. Zeichensequenz nicht beendet
 */
extern int SML3_latin_next(int, const char *, size_t, char *, size_t *);


/** SML3_latin_convert [thread-sicher]:
 * konvertiert String
 * 1.Arg: IO-Flag
 *        - eins aus SML3_LATIN_INPUT_*
 *          (wenn fehlt, wird UTF-8 verwendet, und eventuelle ISO-Zeichen akzeptiert)
 *        - eins aus SML3_LATIN_OUTPUT_*
 *        - evtl. aus SML3_LATIN_MODIF_*
 * 2.Arg: String
 * 3.Arg: Uebergabe: Stringlaenge
 *        Rueckgabe: Anzahl restl. nicht konvertierte Bytes
 *                   oder 0 = OK
 * 4.Arg: Rueckgabe-Gummistring fuer konvertierten String (erhaelt Ende-0)
 * 5.Arg: Beginnposition Rueckgabe-Gummistring
 * Rueckgabe: Anzahl Zeichen im Gummistring ab 5.Arg
 */
extern size_t SML3_latin_convert(int, const char *, size_t *, struct SML3_gummi *, size_t);


/** SML3_latin_toupper [thread-sicher]:
 * macht lateinische Kleinbuchstaben gross
 * 1.Arg: ob String 2.Arg UTF-8 ist: 1 = UTF-8 oder 0 = ISO
 * 2.Arg: String
 * Rueckgabe: allozierter konvertierter String
 */
extern char * SML3_latin_toupper(int, const char *);


/** SML3_latin_tolower [thread-sicher]:
 * macht lateinische Grossbuchstaben klein
 * 1.Arg: ob String 2.Arg UTF-8 ist: 1 = UTF-8 oder 0 = ISO
 * 2.Arg: String
 * Rueckgabe: allozierter konvertierter String
 */
extern char * SML3_latin_tolower(int, const char *);


/** SML3_latin_strlen [thread-sicher]:
 * gibt Anzahl Zeichen eines UTF-8-Strings zurueck
 * 1.Arg: UTF-8-String
 * Rueckgabe: >=0 = Anzahl Zeichen (nicht Bytes!)
 *             -1 = 1.Arg ist kein UTF-8
 */
extern int SML3_latin_strlen(const char *);


/** SML3_latin_strcmp [thread-sicher]:
 * aehnlich strcmp() fuer UTF-8-Strings
 * 1.Arg: UTF-8-String
 * 2.Arg: UTF-8-String
 * 3.Arg: 0 = case-sensitive   (aehnlich strcmp())
 *        1 = case-insensitive (aehnlich strcasecmp())
 * Rueckgabe: -1 = 1.Arg ist kleiner
 *             0 = beide Arg sind gleich
 *             1 = 1.Arg ist groesser
 */
extern int SML3_latin_strcmp(const char *, const char *, int);

#endif /* SML3__LATIN_H_ */
