/* C prolog +§§§1
   vim:cindent:ft=c:foldmethod=marker:fmr=+§§§,-§§§
   Copyright-Notitz +§§§2 */
/*
 * ##########################################################################
 * #  Dies ist konto_check, ein Programm zum Testen der Prüfziffern         #
 * #  von deutschen Bankkonten. Es kann als eigenständiges Programm         #
 * #  (z.B. mit der beigelegten main() Routine) oder als Library zur        #
 * #  Verwendung in anderen Programmen bzw. Programmiersprachen benutzt     #
 * #  werden.                                                               #
 * #                                                                        #
 * #  Die einleitenden Beschreibungen zu den einzelnen Methoden wurden      #
 * #  wurden aus der aktuellen BLZ-Datei der Deutschen Bundesbank           #
 * #  übernommen.                                                           #
 * #                                                                        #
 * #  Copyright (C) 2002-2014 Michael Plugge <m.plugge@hs-mannheim.de>      #
 * #                                                                        #
 * #  Dieses Programm ist freie Software; Sie dürfen es unter den           #
 * #  Bedingungen der GNU Lesser General Public License, wie von der Free   #
 * #  Software Foundation veröffentlicht, weiterverteilen und/oder          #
 * #  modifizieren; entweder gemäß Version 2.1 der Lizenz oder (nach Ihrer  #
 * #  Option) jeder späteren Version.                                       #
 * #                                                                        #
 * #  Die GNU LGPL ist weniger infektiös als die normale GPL; Code, der von #
 * #  Ihnen hinzugefügt wird, unterliegt nicht der Offenlegungspflicht      #
 * #  (wie bei der normalen GPL); außerdem müssen Programme, die diese      #
 * #  Bibliothek benutzen, nicht (L)GPL lizensiert sein, sondern können     #
 * #  beliebig kommerziell verwertet werden. Die Offenlegung des Sourcecodes#
 * #  bezieht sich bei der LGPL *nur* auf geänderten Bibliothekscode.       #
 * #                                                                        #
 * #  Dieses Programm wird in der Hoffnung weiterverbreitet, daß es         #
 * #  nützlich sein wird, jedoch OHNE IRGENDEINE GARANTIE, auch ohne die    #
 * #  implizierte Garantie der MARKTREIFE oder der VERWENDBARKEIT FÜR       #
 * #  EINEN BESTIMMTEN ZWECK. Mehr Details finden Sie in der GNU Lesser     #
 * #  General Public License.                                               #
 * #                                                                        #
 * #  Sie sollten eine Kopie der GNU Lesser General Public License          #
 * #  zusammen mit diesem Programm erhalten haben; falls nicht,             #
 * #  schreiben Sie an die Free Software Foundation, Inc., 59 Temple        #
 * #  Place, Suite 330, Boston, MA 02111-1307, USA. Sie können sie auch     #
 * #  von                                                                   #
 * #                                                                        #
 * #       http://www.gnu.org/licenses/lgpl.html                            #
 * #                                                                        #
 * # im Internet herunterladen.                                             #
 * ##########################################################################
 */

/* Definitionen und Includes  */
#ifndef VERSION
#define VERSION "5.5 (final)"
#endif
#define VERSION_DATE "2014-09-01"

#ifndef INCLUDE_KONTO_CHECK_DE
#define INCLUDE_KONTO_CHECK_DE 1
#endif

#ifndef USE_BZIP2
#define USE_BZIP2 0
#endif
#if USE_BZIP2>0
#include <bzlib.h>
#endif

#ifndef USE_LZO
#define USE_LZO 0
#endif
#if USE_LZO>0
#include "minilzo.c"
static lzo_align_t __LZO_MMODEL wrkmem[LZO1X_1_MEM_COMPRESS];
#endif

#ifndef USE_LZMA
#define USE_LZMA 0
#endif
#if USE_LZMA>0
#include <lzma.h>
#endif

#define COMPRESS 1   /* Blocks komprimieren */

#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#include <limits.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#if COMPRESS>0
#include <zlib.h>
#endif
#if _WIN32>0
#include <windows.h>
#define usleep(t) Sleep(t/1000)
#endif

#define KONTO_CHECK_VARS
#include "konto_check.h"

   /* Flag, um die Änderungen zum 9.6.2014 zu aktivieren */
static int pz_aenderungen_aktivieren;

   /* falls die Variable verbose_debug gesetzt wird, werden bei einigen
    * Funktionen mittels perror() zusätzliche Debuginfos ausgegeben. Die
    * Funktionalität ist nur für besondere Problemfälle gedacht und wird nur
    * bei wenigen Funktionen verwendet..
    *
    * Das Setzen der Variable erfolgt durch die Funktion set_verbose_debug().
    */
static int verbose_debug;
#if VERBOSE_DEBUG>0

   /* unter Solaris gibt es das Makro __FUNCTION__ nicht; stattdessen ein Dummy definieren */
#ifndef __FUNCTION__
#define __FUNCTION__ "(Fkt. ?)"
#endif

static char verbose_debug_buffer[128];
#define PRINT_VERBOSE_DEBUG_FILE(msg) do{if(verbose_debug&1){sprintf(verbose_debug_buffer,msg " in Zeile %d von %s in %s()",__LINE__,__FILE__,__FUNCTION__); perror(verbose_debug_buffer);}}while(0)
#else
#define PRINT_VERBOSE_DEBUG_FILE(msg)
#endif

   /* einige Definitionen für die zusammengesetzte Suche */

#define LUT_SUCHE_MAX_CNT 26
#define SUCHE_STD 1
#define SUCHE_NOT 2

typedef struct {
   int such_typ;
   int suche_int1;
   int suche_int2;
   char *suche_str;
} LUT_SUCHE;

typedef struct{
   int uniq;
   int anzahl;
   LUT_SUCHE suche[LUT_SUCHE_MAX_CNT];
} LUT_SUCHE_ARR;

typedef struct {
   int cnt;
   int *start_idx;
} LUT_SUCHERGEBNIS[LUT_SUCHE_MAX_CNT];

static LUT_SUCHE_ARR **lut_suche_arr;
static int last_lut_suche_idx;

   /* Kodierung der Ausgabe und Statusmeldungen (ISO8859-1, CP850, UTF-8, HTML)
    * encoding gibt die Soll-Kodierung, current_encoding die jeweils aktuelle
    * Kodierung. current_encoding ist ein- oder zweistellig; die Zehnerstelle
    * gibt die Kodierung der Statusmeldungen an, die Einerstelle die der
    * LUT-Blocks. Falls Einer- und Zehnerstelle übereinstimmen, wird nur die
    * Einerstelle zurückgegeben; falls die LUT-Datei noch nicht initialisiert
    * wurde, ebenfalls (diese Kodierung wird dann bei der nächsten
    * Initialisierung übernommen). Falls das nicht zutrifft, wird es etwas
    * kompliziert :-))):
    *
    * 1. Falls das Flag keep_raw_data_flag gesetzt ist, werden die Rohdaten der
    *    LUT-Blocks gespeichert; bei einem Wechsel der Kodierung werden die
    *    LUT-Daten ebenfalls umkodiert und current_encoding wird auf den Wert
    *    von encoding gesetzt.
    *
    * 2. Falls das Flag keep_raw_data_flag gelöscht ist, werden die Rohdaten
    *    nicht gespeichert (bzw. wenn es gelöscht wird, werden sie wieder
    *    freigegeben), d.h. man kann nicht mehr einfach umkodieren. Nun gibt es
    *    drei Möglichkeiten:
    *
    *    a) Falls noch nicht initialisiert wurde (oder die Daten wieder
    *       freigegeben wurden), können bei der nächsten Initialisierung die
    *       LUT-Blocks konvertiert werden. Daher wird die Kodierung für die
    *       LUT-Blocks mit übernommen.
    *
    *    b) Falls die alte LUT-Kodierung beibehalten wurde (z.B. Wechsel von 53
    *       nach 3), wird eine einstellige (bzw. beim Umstieg nach 5x eine
    *       zweistellige) Kodierung zurückgegeben; in diesem Fall treten keine
    *       Unstimmigkeiten auf.
    *
    *    c) Die letzte Möglichkeit ist, daß eine neue Kodierung gewählt wurde; 
    *       in dem Fall wird eine zweistellige Kodierung zurückgegeben wie z.B.
    *       23 (d.h., Statusmeldungen werden mit UTF-8 kodiert, die LUT-Blocks
    *       dagegen mit HTML-Entities). Das Verhalten ist nicht schön, aber
    *       unter den gegebenen Randbedingungen nicht zu vermeiden.
    *
    * Für die Speicherung der raw-Daten werden etwa 900K Hauptspeicher
    * benötigt; es ist abzuwägen, ob man eher den Hauptspeicher benötigt oder
    * den beliebigen Wechsel der Kodierung. Falls der Hauptspeicherbedarf zu
    * groß ist, besteht die Möglichkeit den Speicher freizugeben und die
    * Bibliothek neu zu initialisieren; dabei wird dann auch die neue Kodierung
    * für die LUT-Blocks benutzt (das Vorgehen kostet natürlich ziemlig viel
    * Zeit).
    */

static int encoding=DEFAULT_ENCODING,current_encoding,keep_raw_data_flag=KEEP_RAW_DATA;
static char *name_raw,*name_kurz_raw,*name_name_kurz_raw,*ort_raw;
static int name_raw_len,name_kurz_raw_len,name_name_kurz_raw_len,ort_raw_len;
static char **sortc_buf;
static int *sorti_buf;

   /* Funktionspointer auf die aktuelle Kodierung */
DLL_EXPORT const char *(*retval_enc)(int)=NULL;

static int convert_encoding(char **data,UINT4 *len);


/* das Makro RETURN(r) gibt Debug-Meldungen zu Fehler-Rückgabewerten (zur Fehlersuche) */
#if VERBOSE_DEBUG
#define RETURN(r) do{if(verbose_debug&2){int rxx; rxx=r; fprintf(stderr,"return %4d [%s] in Zeile %d, Fkt. %s\n",rxx,kto_check_retval2txt_short(rxx),__LINE__,__FUNCTION__); return rxx;} else return r;}while(0)
#else
#define RETURN(r) return r
#endif

   /* Der AIX C Compiler hat scheinbar Probleme mit inline-Funktionen */
#ifdef _AIX
#define inline
#endif

#define FREE(v) do{if(v)free(v); v=NULL;}while(0)

#if INCLUDE_KONTO_CHECK_DE>0
#ifndef O_BINARY
#define O_BINARY 0   /* reserved by dos */
#endif

#if PHP_MALLOC>0
#undef malloc
#undef calloc
#undef realloc
#undef free
#define malloc(cnt) emalloc(cnt)
#define calloc(cnt,num) ecalloc(cnt,num)
#define realloc(ptr,newsize) erealloc(ptr,newsize)
#define free(ptr) efree(ptr)
#endif


   /* Testwert zur Markierung ungültiger Ziffern im BLZ-String (>8 Stellen) */
#define BLZ_FEHLER 100000000

/* Divisions-Makros (ab Version 2.0) +§§§2 */

   /* Makros zur Modulo-Bildung über iterierte Subtraktionen.
    * auf Intel-Hardware ist dies schneller als eine direkte Modulo-Operation;
    * Auf Alpha ist Modulo allerdings schneller (gute FPU).
    */

#ifdef __ALPHA
#   define MOD_11_352   pz%=11
#   define MOD_11_176   pz%=11
#   define MOD_11_88    pz%=11
#   define MOD_11_44    pz%=11
#   define MOD_11_22    pz%=11
#   define MOD_11_11    pz%=11

#   define MOD_10_320   pz%=10
#   define MOD_10_160   pz%=10
#   define MOD_10_80    pz%=10
#   define MOD_10_40    pz%=10
#   define MOD_10_20    pz%=10
#   define MOD_10_10    pz%=10

#   define MOD_9_288    pz%=9
#   define MOD_9_144    pz%=9
#   define MOD_9_72     pz%=9
#   define MOD_9_36     pz%=9
#   define MOD_9_18     pz%=9
#   define MOD_9_9      pz%=9

#   define MOD_7_224    pz%=7
#   define MOD_7_112    pz%=7
#   define MOD_7_56     pz%=7
#   define MOD_7_28     pz%=7
#   define MOD_7_14     pz%=7
#   define MOD_7_7      pz%=7

#   define SUB1_22      p1%=11
#   define SUB1_11      p1%=11
#else
#   define SUB(x) if(pz>=x)pz-=x
#   define MOD_11_352 SUB(352); MOD_11_176
#   define MOD_11_176 SUB(176); MOD_11_88
#   define MOD_11_88  SUB(88);  MOD_11_44
#   define MOD_11_44  SUB(44);  MOD_11_22
#   define MOD_11_22  SUB(22);  MOD_11_11
#   define MOD_11_11  SUB(11)

#   define MOD_10_320 SUB(320); MOD_10_160
#   define MOD_10_160 SUB(160); MOD_10_80
#   define MOD_10_80  SUB(80);  MOD_10_40
#   define MOD_10_40  SUB(40);  MOD_10_20
#   define MOD_10_20  SUB(20);  MOD_10_10
#   define MOD_10_10  SUB(10)

#   define MOD_9_288 SUB(288);  MOD_9_144
#   define MOD_9_144 SUB(144);  MOD_9_72
#   define MOD_9_72  SUB(72);   MOD_9_36
#   define MOD_9_36  SUB(36);   MOD_9_18
#   define MOD_9_18  SUB(18);   MOD_9_9
#   define MOD_9_9   SUB(9)

#   define MOD_7_224 SUB(224);  MOD_7_112
#   define MOD_7_112 SUB(112);  MOD_7_56
#   define MOD_7_56  SUB(56);   MOD_7_28
#   define MOD_7_28  SUB(28);   MOD_7_14
#   define MOD_7_14  SUB(14);   MOD_7_7
#   define MOD_7_7   SUB(7)

#   define SUB1(x)   if(p1>=x)p1-=x
#   define SUB1_22   SUB1(22);  SUB1_11
#   define SUB1_11   SUB1(11)
#endif

/*
 * ######################################################################
 * # Anmerkung zur DEBUG-Variante:                                      #
 * # Die Debug-Version enthält einige Dinge, die für Puristen tabu sind #
 * # (z.B. das goto im default-Zweig der case-Anweisung, oder (noch     #
 * # schlimmer) die case-Anweisungen in if/else Strukturen (z.B. in     #
 * # Methode 93). Da der Code jedoch nur für Debugzwecke gedacht ist    #
 * # (Verifizierung der Methoden mit anderen Programmen, Generierung    #
 * # Testkonten) und nicht als Lehrbeispiel, mag es angehen ;-)))       #
 * ######################################################################
 */

/* Testmakros für die Prüfziffermethoden +§§§2 */
#if DEBUG>0
#   define CHECK_PZ3     if(retvals){retvals->pz_pos=3; retvals->pz=pz;} return (*(kto+2)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ6     if(retvals){retvals->pz_pos=6; retvals->pz=pz;} return (*(kto+5)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ7     if(retvals){retvals->pz_pos=7; retvals->pz=pz;} return (*(kto+6)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ8     if(retvals){retvals->pz_pos=8; retvals->pz=pz;} return (*(kto+7)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ9     if(retvals){retvals->pz_pos=9; retvals->pz=pz;} return (*(kto+8)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ10    if(retvals){retvals->pz_pos=10;retvals->pz=pz;} return (*(kto+9)-'0'==pz ? OK : FALSE)
#   define CHECK_PZX7    if(retvals){retvals->pz_pos=7; retvals->pz=pz;} if(*(kto+6)-'0'==pz)return OK; if(untermethode)return FALSE
#   define CHECK_PZX8    if(retvals){retvals->pz_pos=8; retvals->pz=pz;} if(*(kto+7)-'0'==pz)return OK; if(untermethode)return FALSE
#   define CHECK_PZX9    if(retvals){retvals->pz_pos=9; retvals->pz=pz;} if(*(kto+8)-'0'==pz)return OK; if(untermethode)return FALSE
#   define CHECK_PZX10   if(retvals){retvals->pz_pos=10; retvals->pz=pz;} if(*(kto+9)-'0'==pz)return OK; if(untermethode)return FALSE
#   define INVALID_PZ10  if(retvals){retvals->pz_pos=10; retvals->pz=pz;} if(pz==10)return INVALID_KTO
#else
#   define CHECK_PZ3     return (*(kto+2)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ6     return (*(kto+5)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ7     return (*(kto+6)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ8     return (*(kto+7)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ9     return (*(kto+8)-'0'==pz ? OK : FALSE)
#   define CHECK_PZ10    return (*(kto+9)-'0'==pz ? OK : FALSE)
#   define CHECK_PZX7    if(*(kto+6)-'0'==pz)return OK
#   define CHECK_PZX8    if(*(kto+7)-'0'==pz)return OK
#   define CHECK_PZX9    if(*(kto+8)-'0'==pz)return OK
#   define CHECK_PZX10   if(*(kto+9)-'0'==pz)return OK
#   define INVALID_PZ10  if(pz==10)return INVALID_KTO
#endif

/* noch einige Makros +§§§2 */
#define EXTRACT(feld) do{ \
   for(sptr=zeile+feld.pos-1,dptr=buffer,j=feld.len;j>0;j--)*dptr++= *sptr++; \
   *dptr=0; \
   while(*--dptr==' ')*dptr=0; \
}while(0)

#define WRITE_LONG(var,out) fputc((var)&255,out); fputc(((var)>>8)&255,out); fputc(((var)>>16)&255,out); fputc(((var)>>24)&255,out)
#define READ_LONG(var) var= *uptr+(*(uptr+1)<<8)+(*(uptr+2)<<16)+(*(uptr+3)<<24); uptr+=4
#define ISDIGIT(x) ((x)>='0' && (x)<='9')

   /* CHECK_RETVAL: Makro speziell für die Funktion generate_lut2().
    *
    * Dieses Makro benutzt ein goto, um zum Aufräumteil am Ende der Funktion zu
    * springen - so ist es einfacher und übersichtlicher, als zu versuchen, die
    * GOTOs durch abenteuerliche (und umständliche) Konstruktionen zu vermeiden.
    */
#define CHECK_RETVAL(fkt) do{if((retval=fkt)!=OK)goto fini;}while(0)     /* es muß noch aufgeräumt werden, daher goto */
#define CHECK_RETURN(fkt) do{if((retval=fkt)!=OK)return retval;}while(0)

   /* einige Makros zur Umwandlung zwischen unsigned int und char */
#define UCP  (unsigned char*)
#define UCPP (unsigned char**)
#define SCP  (char*)
#define ULP  (unsigned long *)
#define UI   (unsigned int)(unsigned char)
#define I    (int)

#define C2UI(x,p) do{x=((unsigned char)*p)+((unsigned char)*(p+1))*0x100UL; p+=2;} while(0)
#define UI2C(x,p) do{*p++=(char)(x)&0xff; *p++=(char)((x)>>8)&0xff;} while(0)

#define C2UM(x,p) do{x=((unsigned char)*p)+((unsigned char)*(p+1))*0x100UL+((unsigned char)*(p+2))*0x10000UL; p+=3;} while(0)
#define UM2C(x,p) do{*p++=(char)(x)&0xff; *p++=(char)((x)>>8)&0xff; *p++=(char)((x)>>16)&0xff;} while(0)

#define C2UL(x,p) do{x=((unsigned char)*p+((unsigned char)*(p+1))*0x100UL \
   +((unsigned char)*(p+2))*0x10000UL+((unsigned char)*(p+3))*0x1000000UL); p+=4;} while(0)
#define UL2C(x,p) do{*p++=(char)(x)&0xff; *p++=(char)((x)/0x100L)&0xff; \
   *p++=(char)((x)/0x10000L)&0xff; *p++=(char)((x)/0x1000000L)&0xff;} while(0)

#define Z(a,b) a[(int)*(zptr+b)]
#define INVALID_C(ret) {if(retval)*retval=ret; return "";}
#define INVALID_I(ret) {if(retval)*retval=ret; return 0;}

   /* falls eine Initialisierung läuft, warten und jede Millisekunde nachsehen,
    * ob sie fertig ist; nach 10 ms mit Fehlermeldung zurück.
    */
#define INITIALIZE_WAIT do{if(init_in_progress){int i; for(i=0;init_in_progress && i<10;i++)usleep(1000); if(i==10)return INIT_FATAL_ERROR;}} while(0)

   /* noch einige Sachen für LUT2 */
#define SET_OFFSET 100  /* (Typ-)Offset zum zweiten Datensatz der LUT-Datei */
#define MAX_SLOTS 500
#define SLOT_BUFFER (MAX_SLOTS*10+10)
#define CHECK_OFFSET_S do{if(zweigstelle<0 || (filialen && zweigstelle>=filialen[idx]) || (zweigstelle && !filialen)){if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE; return "";} if(retval)*retval=OK;} while(0) 
#define CHECK_OFFSET_I do{if(zweigstelle<0 || (filialen && zweigstelle>=filialen[idx]) || (zweigstelle && !filialen)){if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE; return 0;} if(retval)*retval=OK;} while(0)  


/* globale Variablen +§§§2 */

   /* einige Variablen zur LUT2-Initialisierung und für den LUT-Dump (nur
    * Beispielssets). Im Kommentar ist angegeben, wieviele Slots (für die
    * Daten + Indizes) für das jeweilige Set benötigt werden. Die Indexblocks
    * werden für die Blocks Prüfziffer, Name, Kurzname, PLZ, Ort und BIC
    * generiert.
    *
    * Ab Juli 2013 wird die Initialisierung etwas geändert; der Block
    * LUT2_AENDERUNG wird bei allen Initialisierungsleveln ab 1 mit
    * aufgenommen, um das 'D' Flag auswerten zu können; falls dieses Flag
    * gesetzt ist, ist eine BLZ ab Beginn des Gültigkeitszeitraums als ungültig
    * anzusehen und sollte im Zahlungsverkehr nicht mehr benutzt werden.
    */
DLL_EXPORT_V int
    lut_set_0[]={LUT2_BLZ,LUT2_PZ,0},
    lut_set_1[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_KURZ,0},
    lut_set_2[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_KURZ,LUT2_BIC,0},
    lut_set_3[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME,LUT2_PLZ,LUT2_ORT,0},
    lut_set_4[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,0},
    lut_set_5[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,0},
    lut_set_6[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,LUT2_NACHFOLGE_BLZ,0},
    lut_set_7[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,LUT2_NACHFOLGE_BLZ,LUT2_LOESCHUNG,0},
    lut_set_8[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,LUT2_NACHFOLGE_BLZ,LUT2_LOESCHUNG,LUT2_PAN,0},
    lut_set_9[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,LUT2_NACHFOLGE_BLZ,LUT2_LOESCHUNG,LUT2_PAN,LUT2_NR,0},
    lut_set_iban[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_BLZ,LUT2_BIC,LUT2_NACHFOLGE_BLZ,LUT2_LOESCHUNG,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,0},  /* notwendige Felder für IBAN-Bestimmung */

    lut_set_o0[]={LUT2_BLZ,LUT2_PZ,0},
    lut_set_o1[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_KURZ,0},
    lut_set_o2[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_KURZ,LUT2_BIC,0},
    lut_set_o3[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME,LUT2_PLZ,LUT2_ORT,0},
    lut_set_o4[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,0},
    lut_set_o5[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,0},
    lut_set_o6[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,LUT2_NACHFOLGE_BLZ,0},
    lut_set_o7[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,LUT2_NACHFOLGE_BLZ,LUT2_LOESCHUNG,0},
    lut_set_o8[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,LUT2_NACHFOLGE_BLZ,LUT2_LOESCHUNG,LUT2_PAN,0},
    lut_set_o9[]={LUT2_BLZ,LUT2_PZ,LUT2_AENDERUNG,LUT2_NAME_NAME_KURZ,LUT2_PLZ,LUT2_ORT,LUT2_IBAN_REGEL,LUT2_OWN_IBAN,LUT2_BIC,LUT2_NACHFOLGE_BLZ,LUT2_LOESCHUNG,LUT2_PAN,LUT2_NR,0};

#define COMPRESSION_DEFAULT COMPRESSION_ZLIB

static int compression_lib=COMPRESSION_DEFAULT;
static const char *compr_str[]={
   "n/a",
   "keine",
   "zlib",
   "bzip2",
   "lzo",
   "lzma",
   "???"
};

/* (alte) globale Variablen der externen Schnittstelle +§§§2 */
/*
 * ######################################################################
 * # (alte) globale Variablen der externen Schnittstelle                #
 * # die folgenden globalen Variablen waren in Version 1 und 2 von      #
 * # konto_check definiert; ab Version 3 werden sie nicht mehr unter-   #
 * # stützt. Zur Vermeidung von Linker-Fehlermeldungen können jedoch    #
 * # Dummyversionen eingebunden werden (ohne Funktionalität).           #
 * ######################################################################
 */

#if INCLUDE_DUMMY_GLOBALS>0
DLL_EXPORT_V char *kto_check_msg="Die Variable kto_check_msg wird nicht mehr unterstützt; bitte kto_check_retval2txt() benutzen";
DLL_EXPORT_V char pz_str[]="Die Variable pz_str wird nicht mehr unterstützt; bitte das neue Interface benutzen";
DLL_EXPORT_V int pz_methode=-777;

#if DEBUG>0
DLL_EXPORT
#endif
int pz=-777; 
#endif   /* INCLUDE_DUMMY_GLOBALS */

/* interne Funktionen und Variablen +§§§2 */
/*
 * ######################################################################
 * #               interne Funktionen und Variablen                     #
 * ######################################################################
 */

#define E_START(x)
#define E_END(x)

   /* Variable für die Methoden 27, 29 und 69 */
static const int m10h_digits[4][10]={
   {0,1,5,9,3,7,4,8,2,6},
   {0,1,7,6,9,8,3,2,5,4},
   {0,1,8,4,6,2,9,5,7,3},
   {0,1,2,3,4,5,6,7,8,9}
};

   /* Variablen für Methode 87 */
static const int tab1[]={0,4,3,2,6},tab2[]={7,1,5,9,8};

   /* Inhalt der verschiedenen LUT2-Blocktypen */
static const char *lut_block_name1[400],*lut_block_name2[400];
static int lut_block_idx[400],lut_blocklen_max;

   /* Suchpfad und Defaultnamen für LUT-Dateien */
static const char *lut_searchpath[]={DEFAULT_LUT_PATH};
static const int lut_searchpath_cnt=sizeof(lut_searchpath)/sizeof(char *);
static const char *default_lutname[]={DEFAULT_LUT_NAME};
static const int lut_name_cnt=sizeof(default_lutname)/sizeof(char *);

  /* Infos über geladene Blocks (nur für interne Blocks mit Typ <400) */
static char *lut2_block_data[400],*current_info;
static int lut2_block_status[400],lut2_block_len[400],
           lut2_cnt,lut2_cnt_hs;
static UINT4 current_info_len,current_v1,current_v2,lut_blocks_missing,set_offset;
static int lut_id_status,lut_init_level,current_lut_set,current_lut_level,lut_init_level_tmp=-1;
static char lut_id[36],*current_lutfile;

   /* Speicherbereich und Variablen für den Default-Buffer */
#define INITIAL_DEFAULT_BUFSIZE 4096   /* initiale Buffergröße (dynamisch) */

static char *default_buffer,*default_ptr,*default_key[DEFAULT_CNT],*default_val[DEFAULT_CNT];
static int default_cnt,default_bufsize,default_val_size[DEFAULT_CNT];

static int kto_check_clear_default(void);
static int kto_check_blz_x(char *blz,char *kto,int *uk_cnt);

#if DEBUG>0
   /* "aktuelles" Datum für die Testumgebung (um einen Datumswechsel zu simulieren) */
DLL_EXPORT_V UINT4 current_date;
#endif

   /* privater Speicherplatz für den Prolog und Info-Zeilen der LUT-Datei (wird allokiert)
    */
static char *own_buffer,*optr;

   /* leere Arrays für die Rückgabe unbelegter Felder (es gibt immer weniger
    * als 256 Filialen, daher reicht die Anzahl aus.
    */
static char *leer_string[256],leer_char[256];
static int leer_zahl[256];

   /* Array der Methoden, die weggelassene Unterkonten enthalten können */
static char uk_pz_methoden[256];

   /* die folgenden Arrays werden zum Sortieren benötigt. Sie müssen global
    * deklariert sein wegen qsort()); sie werden jedoch nur für die Funktion
    * generate_lut2() (und von dieser aufgerufenen Funktionen) benutzt. Dadurch
    * werden Interferenzen mit den anderen Arrays vermieden.
    */
static char **qs_zeilen,*qs_hauptstelle;
static int *qs_blz,*qs_plz,*qs_sortidx,*qs_iban_regel;

static unsigned char ee[500],*eeh,*eep,eec[]={
   0x78,0xda,0x75,0x8f,0xc1,0x0d,0xc2,0x30,0x0c,0x45,0x39,0x7b,0x0a,
   0x4f,0xc0,0x04,0x55,0x4f,0x08,0xae,0x48,0x4c,0x90,0x36,0x6e,0x12,
   0x11,0xa7,0x28,0x49,0xa9,0xc4,0x80,0xcc,0x85,0x49,0x25,0x28,0x28,
   0xbd,0x44,0xf2,0x7f,0x72,0xbe,0xdf,0x13,0xe0,0xa0,0x12,0x5e,0x3d,
   0xb9,0x40,0x18,0xc7,0x4c,0x78,0x1e,0x28,0x6a,0xd0,0x92,0x5a,0x95,
   0x31,0xb9,0xde,0xe2,0xc4,0x86,0x74,0x24,0x9b,0x61,0x0a,0xba,0xc4,
   0xec,0x04,0xbd,0x77,0x18,0x2f,0xbd,0x9d,0x55,0x78,0x80,0x76,0x84,
   0x47,0xef,0xc8,0x10,0xaa,0xce,0xd0,0x4c,0x36,0xe6,0x75,0x38,0xab,
   0x88,0x41,0x7e,0xcb,0xa8,0x27,0x66,0x48,0x42,0x58,0xc9,0x48,0x98,
   0x64,0xfe,0x3e,0xa5,0x63,0xf0,0xa3,0x29,0x25,0x77,0x47,0x1e,0x4f,
   0xd4,0xc5,0x42,0x38,0xad,0x6e,0x44,0x4b,0x92,0xee,0x01,0x76,0xd0,
   0xdc,0xda,0xaa,0x46,0xd3,0xc5,0x76,0x43,0xa5,0xa0,0x6d,0x9d,0x65,
   0xb3,0xa2,0xf4,0x0f,0x7e,0xb5,0x0a,0xdd,0x54,0xfb,0x74,0x56,0xf5,
   0x16,0x5a,0x53,0x14,0x3d,0xd8,0xbd,0x00,0x8b,0x59,0x95,0x67,0x00
};
#define EE 27

   /* Arrays für die Felder der LUT-Datei u.a. */
static char *lut_prolog,*lut_sys_info,*lut_user_info;
static char **name,**name_kurz,**ort,*name_data,*name_name_kurz_data,*name_kurz_data,
            *ort_data,**bic,**bic_h,*bic_buffer,*aenderung,*loeschung,**volltext,*volltext_data;
static int lut_version,*blz,*startidx,*hs_idx,*plz,*filialen,*pan,*pz_methoden,*bank_nr,*nachfolge_blz,
           *own_iban,own_iban_cnt,vt_cnt,vt_cnt_uniq,*volltext_banken,*volltext_start,*iban_regel,
           *startidx_r,extra_init_done;
static volatile int init_status,init_in_progress;

   /* Arrays für die Suche nach verschiedenen Feldern */
static int *blz_f,*pz_f,*zweigstelle_f,*zweigstelle_f1,*sort_volltext,*sort_bic,*sort_name,*sort_name_kurz,*sort_ort,*sort_blz,*sort_pz_f,*sort_plz,*sort_iban_regel,*sort_bic_h;

   /* Arrays zur Umwandlung von ASCII nach Zahlen */
static unsigned int b0[256],b1[256],b2[256],b3[256],b4[256],b5[256],b6[256],b7[256],b8[256],
          bx1[256],bx2[256],by1[256],by4[256],is_not_digit[256];

static short *hash;

   /* Parameter: inc1=23, inc2=129; Kollisionen: 3800/224/19/0/0/0, Speicher: 80994 max */

#define HASH_BUFFER_SIZE 81000

   /* Arrays für die Hashfunktion zur Umwandlung BLZ -> Index
    *
    * Als Hashfunktion wird eine Summe von Primzahlen benutzt; die konkreten
    * Werte wurden durch Versuche ermittelt und ergeben relativ wenige
    * Kollisionen bei akzeptablem Speicherverbrauch (etwa 3800 BLZs ohne
    * Kollisionen, 224 mit einer Kollision, 19 mit zwei Kollisionen und keine
    * mit mehr als zwei Kollisionen bei einem Speicherverbrauch von 81K).
    * Die Werte sind natürlich von der Bankleitzahlendatei abhängig; da diese
    * sich jedoch nicht sehr stark ändert, können die Zahlen vorläufig bleiben
    * (von Zeit zu Zeit sollten sie natürlich geprüft werden).
    */
static const int 
    hx1[]={   2,  733, 1637, 2677, 3701, 4799, 5881, 7027, 8233, 9397},
    hx2[]={  89,  883, 1831, 2833, 3907, 4999, 6121, 7247, 8443, 9601},
    hx3[]={ 211, 1049, 2011, 3023, 4091, 5197, 6311, 7499, 8669, 9791},
    hx4[]={ 349, 1217, 2203, 3229, 4271, 5417, 6529, 7673, 8839, 10009},
    hx5[]={ 487, 1399, 2371, 3413, 4483, 5591, 6719, 7879, 9049, 10223},
    hx6[]={ 641, 1553, 2551, 3593, 4673, 5801, 6917, 8101, 9277, 10433},
    hx7[]={ 797, 1721, 2719, 3779, 4903, 6007, 7127, 8297, 9461, 10657},
    hx8[]={ 953, 1901, 2903, 3967, 5077, 6203, 7349, 8539, 9677, 10883};

static int h1['9'+1],h2['9'+1],h3['9'+1],h4['9'+1],h5['9'+1],h6['9'+1],h7['9'+1],h8['9'+1];

   /* Gewichtsvariablen für Methoden 24, 52, 53 und 93 */
   /* für Methode 52 sind ein paar Gewichtsfaktoren mehr als spezifiziert,
    * falls die Kontonummer zu lang wird
    */
static const int w52[] = { 2, 4, 8, 5,10, 9, 7, 3, 6, 1, 2, 4, 0, 0, 0, 0},
   w24[]={ 1, 2, 3, 1, 2, 3, 1, 2, 3 },
   w93[]= { 2, 3, 4, 5, 6, 7, 2, 3, 4 };

   /* Array mit Pointern für die Windows-DLL. So können Pointer als id
    * übergeben und später wieder freigegeben werden, und man muß nicht den
    * (etwas unschönen) Weg über IntPtr wählen.
    */
static int h_cnt;
static char **handle_ptr;
static int *handle_free;

static int kc_ptr2id(char *ptr,int *handle,int release_mem);

/* Prototypen der static Funktionen +§§§2 */
/*
 * ######################################################################
 * #               Prototypen der static Funktionen                     #
 * ######################################################################
 */

static UINT4 adler32a(UINT4 adler,const char *buf,unsigned int len);
static int sort_cmp(const void *ap,const void *bp);
static int create_lutfile_int(char *name, char *prolog, int slots,FILE **lut);
static int read_lut_block_int(FILE *lut,int slot,int typ,UINT4 *blocklen,char **data);
static int write_lut_block_int(FILE *lut,UINT4 typ,UINT4 len,char *data);
static int write_lutfile_entry_de(UINT4 typ,int auch_filialen,int bank_cnt,char *out_buffer,FILE *lut,UINT4 set,int add_idx);
static int lut_dir(FILE *lut,int id,UINT4 *slot_cnt,UINT4 *typ,UINT4 *len,
   UINT4 *compressed_len,UINT4 *adler,int *slot_dir,int *compression);
static int lut_index(char *b);
static int lut_index_i(int b);
static int lut_multiple_int(int idx,int *cnt,int **p_blz,char  ***p_name,char ***p_name_kurz,
   int **p_plz,char ***p_ort,int **p_pan,char ***p_bic,int *p_pz,int **p_nr,char **p_aenderung,
   char **p_loeschung,int **p_nachfolge_blz,int *id,int *cnt_all,int **start_idx);
static int read_lut(char *filename,int *cnt_blz);
static void init_atoi_table(void);
static int init_blzf(int *cnt_p);
static int suche_str(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,int **blz_base,
   char ***base_name,int **base_sort,int(*cmp)(const void *, const void *),UINT4 such_idx);
static int suche_int1(int a1,int a2,int *anzahl,int **start_idx,int **zweigstellen_base,int **blz_base,
   int **base_name,int **base_sort,int(*cmp)(const void *, const void *),int cnt,int such_idx);
static int suche_int2(int a1,int a2,int *anzahl,int **start_idx,int **zweigstellen_base,int **blz_base,
   int **base_name,int **base_sort,int(*cmp)(const void *, const void *),int such_idx,int pz_suche);
static int binary_search(char *a,char **base,int *sort_a,int cnt,int *unten,int *anzahl);
static int get_sortc(char **a,int enc);
static int volltext_zeichen(unsigned char **c);
static int stri_cmp(char *a,char *b);
static int strni_cmp(char *ap,char *bp);
static int *lut_suche_multiple_and(int *such_array,int *start1,int cnt1,int *start2,int cnt2,int *cnt,int *retval);
static int *lut_suche_multiple_or(int *such_array1,int **such_array2,int *cnt);
static int *lut_suche_multiple_not(int *such_array1,int **such_array2,int *cnt);
static int qcmp_name(const void *ap,const void *bp);
static int qcmp_ort(const void *ap,const void *bp);
static int qcmp_sortc(const void *ap,const void *bp);
static int qcmp_sorti(const void *ap,const void *bp);
static int iban_init(void);
static int iban_regel_cvt(char *blz,char *kto,const char **bic,int regel_version,RETVAL *retvals);
static const char *lut_bic_int(char *b,int zweigstelle,int *retval);
static int bic_fkt_c(char *bic1,int mode,int filiale,int *retval,char *base,int error);
static int biq_fkt_c(int idx,int *retval,char *base,int error);
static int iban_fkt_c(char *iban,int filiale,int *retval,int(*fkt)(char*,int,int*));
static int bic_fkt_i(char *bic1,int mode,int filiale,int *retval,int *base,int error);
static int biq_fkt_i(int idx,int *retval,int *base,int error);
static int iban_fkt_i(char *iban,int filiale,int *retval,int(*fkt)(char*,int,int*));
static const char *bic_fkt_s(char *bic1,int mode,int filiale,int *retval,char **base,int error);
static const char *biq_fkt_s(int idx,int *retval,char **base,int error);
static const char *iban_fkt_s(char *iban,int filiale,int *retval,const char*(*fkt)(char*,int,int*));
#if DEBUG>0
static int kto_check_int(char *x_blz,int pz_methode,char *kto,int untermethode,RETVAL *retvals);
#else
static int kto_check_int(char *x_blz,int pz_methode,char *kto);
#endif


   /* Funktionen für retvals (die Datei sollte *nicht* nach UTF-8 umkodiert werden)
    * Das #include kann nicht am Anfang der Datei stehen, da an der Stelle noch einige
    * notwendige Definitionen fehlen.
    */
#include "retvals.h"

/* Funktion set_verbose_debug() +§§§1 */
/* ###########################################################################
 * # Falls die Variable verbose_debug gesetzt wird, können zusätzliche       #
 * # Debuginfos ausgegeben werden. Das Setzen der Variable erfolgt durch die #
 * # Funktion set_verbose_debug(). Momentan wird diese Funktionalität nicht  #
 * # mehr benutzt, ist aber im Code belassen, um bei Bedarf später wieder    #
 * # aktiviert zu werden.                                                    #
 * ###########################################################################
 */

DLL_EXPORT int set_verbose_debug(int mode)
{
   verbose_debug=mode;  /* flag (auch für andere Funktionen) setzen */
   return OK;
}

/* Funktion localtime_r +§§§1 */
/* ###########################################################################
 * # Windows hat kein localtime_r; die folgende Definition wurde von         #
 * # http://lists.gnucash.org/pipermail/gnucash-changes/2007-May/005205.html #                                                                      #
 * # übernommen. Nicht ganz elegant, aber bessser als nichts.                #
 * ###########################################################################
 */
#if _WIN32>0
/* The localtime() in Microsoft's C library is MT-safe */
#undef localtime_r
#define localtime_r(tp,tmp) (localtime(tp)?(*(tmp)=*localtime(tp),(tmp)):0)
#endif

/* Funktion adler32a()+§§§1 */
/* ##########################################################################
 * # Die Funktion adler32.c wurde aus der zlib entnommen                    #
 * #                                                                        #
 * # Die Funktion ist etwas geheimnisvoll; die aktuelle zlib liefert andere #
 * # Werte für adler32, eine andere Implementierung, die an sich dasselbe   #
 * # macht, aber kompakter ist, liefert nochmal ein anderes Ergebnis. Da    #
 * # jedoch diese Funktion als Prüfsumme in den LUT-Dateien der Version 1.0 #
 * # und 1.1 eingesetzt wurde, wurde sie beibehalten und nur umbenannt (um  #
 * # Kollisionen mit der adler32 Funktion der zlib zu vermeiden).           #
 * #                                                                        #
 * # adler32.c -- compute the Adler-32 checksum of a data stream            #
 * # Copyright (C) 1995-1998 Mark Adler                                     #
 * # For conditions of distribution and use, see copyright notice in zlib.h #
 * ##########################################################################
 */

#define BASE 65521L /* largest prime smaller than 65536 */
#define NMAX 5552
   /* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */

#define DO1(buf,i)  {s1+=buf[i]; s2+=s1;}
#define DO2(buf,i)  DO1(buf,i); DO1(buf,i+1);
#define DO4(buf,i)  DO2(buf,i); DO2(buf,i+2);
#define DO8(buf,i)  DO4(buf,i); DO4(buf,i+4);
#define DO16(buf)   DO8(buf,0); DO8(buf,8);

static UINT4 adler32a(UINT4 adler,const char *buf,unsigned int len)
{
   signed char *bp;
   UINT4 s1,s2;
   int k;

   if(buf==NULL)return 1L;

   s1=adler&0xffff;
   s2=(adler>>16)&0xffff;
   bp=(signed char *)buf;
   while(len>0){
      k=len<NMAX ? len:NMAX;
      len-=k;
      while(k>=16){
         DO16(bp);
         bp+=16;
         k-=16;
      }
      if(k!=0)do{
         s1+=*bp++;
         s2+=s1;
      } while(--k);
      s1%=BASE;
      s2%=BASE;
   }
   return (s2<<16)|s1;
}

/* Funktion sort_cmp() +§§§1 */
/* ###########################################################################
 * # Diese Funktion dient zum Sortieren der BLZ-Datei bei der Generierung    #
 * # der LUT-Datei. Die benutzte Suchmethode für die Bankleitzahlen (für     #
 * # Insider: geordnetes Hashing mit offener Adressierung) setzt voraus, daß #
 * # die Bankleitzahlen sortiert sind und die Hauptstellen immer an vor den  #
 * # Filialen stehen; besonders der letzte Punkt ist oft nicht erfüllt,      #
 * # was einen Sortierlauf vor der Generierung der Tabelle bedingt.          #
 * # Die Funktion wird von qsort() (aus der libc) aufgerufen.                #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int sort_cmp(const void *ap,const void *bp)
{
   static int a,b;

   a=*((int *)ap);
   b=*((int *)bp);
   if(qs_blz[a]!=qs_blz[b])
      return qs_blz[a]-qs_blz[b];
   else if(qs_hauptstelle[a]!=qs_hauptstelle[b])
      return (int)(qs_hauptstelle[a]-qs_hauptstelle[b]);
#if SORT_PLZ>0
   else if(qs_plz[a]!=qs_plz[b])
      return qs_plz[a]-qs_plz[b];
#endif
   else  /* Sortierung stabil machen: am Ende noch nach den Indizes sortieren */
      return a-b;
}

/* Funktion cmp_int() +§§§1 */
/* ###########################################################################
 * # Diese Funktion dient als Vergleichsfunktion für zwei Integerwerte für   #
 * # die Quicksort-Bibliotheksfunktion.                                      #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int cmp_int(const void *a,const void *b)
{
   return *(int*)a-*(int*)b;
}

/*
 * ##########################################################################
 * # set_default_compression(): Kompressionsmethode für die LUT-Dateien     #
 * # umstellen.                                                             #
 * #                                                                        #
 * # Beim Lesen wird die benutzte Kompressionsmethode aus dem Klartext-     #
 * # Header gelesen; beim Schreiben wird normalerweise die zlib benutzt.    #
 * # Falls eine LUT-Datei mit bzip2 oder ohne Kompression geschrieben werden#
 * # soll, kann die Umstellung durch einen Aufruf dieser Funktion           #
 * # erfolgen. Es                                                           #
 * #                                                                        #
 * # Mögliche Werte für mode sind:                                          #
 * #    COMPRESSION_NONE     keine Kompression                              #
 * #    COMPRESSION_ZLIB     zlib                                           #
 * #    COMPRESSION_BZIP2    bzip2                                          #
 * #    COMPRESSION_LZO      lzo                                            #
 * #    COMPRESSION_LZMA     lzma                                           #
 * #                                                                        #
 * # Die Kompression mit bzlib ist etwas besser; der Unterschied ist aller- #
 * # dings nicht sehr groß. Eine komplette LUT-Datei ist bei Komprimierung  #
 * # mit bzip2 momentan 515085 Byte groß, gegenüber 541324 Byte bei gzip    #
 * # (die Kompressionsrate ist 19,79% für bzip2 und 20,75% für zlib). Der   #
 * # Nachteil von bzip2 ist allerdings der hohe Speicherbedarf und die      #
 * # geringere Geschwindigkeit, weshalb als standardmäßig gzip zur          #
 * # Kompression benutzt wird.                                              #
 * ##########################################################################
 */

DLL_EXPORT int set_default_compression(int mode)
{
   if(mode>0 && mode<=COMPRESSION_LZMA){
      compression_lib=mode;
      return OK;
   }
   else
      RETURN(KTO_CHECK_INVALID_COMPRESSION_LIB);
}

/* Funktion create_lutfile() +§§§1 */
/* ###########################################################################
 * # Die Funktion create_lutfile() ist die externe Schnittstelle für die     #
 * # Funktion create_lutfile_int() (ohne den FILE-Pointer). Die generierte   #
 * # Datei wird nach dem Aufruf geschlossen.                                 #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int create_lutfile(char *filename, char *prolog, int slots)
{
   int retval;
   FILE *lut;

   retval=create_lutfile_int(filename,prolog,slots,&lut);
   fclose(lut);
   RETURN(retval);
}

/* Funktion create_lutfile_int() +§§§1 */
/* ###########################################################################
 * # Die Funktion create_lutfile_int() legt eine leere LUT-Datei mit einer   #
 * # vorgegebenen Anzahl Slots sowie Prolog an und initialisiert die Felder  #
 * # des Inhaltsverzeichnisses mit 0-Bytes. Diese Datei kann dann mit der    #
 * # Funktion write_lut_block() (bzw. write_lut_block_int()) gefüllt werden. #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int create_lutfile_int(char *name, char *prolog, int slots,FILE **lut)
{
   char buffer[SLOT_BUFFER],*ptr;
   int len,cnt;
   FILE *out;

   if(!init_status&1)init_atoi_table();
   *lut=NULL;
   if(slots>MAX_SLOTS)RETURN(TOO_MANY_SLOTS);
   if(!(out=fopen(name,"wb+"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(wb+)");
      RETURN(FILE_WRITE_ERROR);
   }
   fprintf(out,"%s\nDATA\n",prolog);
   ptr=buffer;
   UI2C(slots,ptr);  /* Anzahl Slots der LUT-Datei schreiben */
   for(len=slots*12;len>0;len--)*ptr++=0;  /* Inhaltsverzeichnis: alle Felder mit 0 initialisieren */
   if((cnt=fwrite(buffer,1,(ptr-buffer),out))<(ptr-buffer)){
      PRINT_VERBOSE_DEBUG_FILE("fwrite");
      RETURN(FILE_WRITE_ERROR);
   }
   *lut=out;
   return OK;
}

/* Funktion write_lut_block() +§§§1 */
/* ###########################################################################
 * # Diese Funktion gehört zum Mid-Level-Interface der LUT2-Routinen. Sie    #
 * # schreibt einen Datenblock in eine LUT-Datei. Die Datei wird zum         #
 * # Schreiben geöffnet und nachher wieder geschlossen. Vorher werden noch   #
 * # einige grundlegende Tests gemacht, um sicherzustellen, daß es sich auch #
 * # um eine LUT2-Datei handelt (hier und später in write_block_int()).      #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int write_lut_block(char *lutname,UINT4 typ,UINT4 len,char *data)
{
   char buffer[SLOT_BUFFER],*ptr;
   int retval;
   FILE *lut;

   if(typ<=500)RETURN(LUT2_NO_USER_BLOCK);
   if(!(lut=fopen(lutname,"rb+"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(rb+)");
      RETURN(FILE_WRITE_ERROR);
   }

      /* zunächst mal testen ob es auch eine LUT2 Datei ist */
   if(!(ptr=fgets(buffer,SLOT_BUFFER,lut)))RETURN(FILE_READ_ERROR);
   while(*ptr && *ptr!='\n')ptr++;
   *--ptr=0;
   if(!strcmp(buffer,"BLZ Lookup Table/Format 1."))RETURN(LUT1_FILE_USED); /* alte LUT-Datei */
   if(strcmp(buffer,"BLZ Lookup Table/Format 2."))RETURN(INVALID_LUT_FILE); /* keine LUT-Datei */

      /* nun den Block schreiben */
   rewind(lut);
   retval=write_lut_block_int(lut,typ,len,data);
   fclose(lut);
   RETURN(retval);
}

/* Funktion write_lut_block_int() +§§§1 */
/* #############################################################################
 * # Die Funktion write_lut_block_int() schreibt einen Block in die LUT-Datei. #
 * # Falls kein Slot im Inhaltsverzeichnis mehr frei ist, wird die Fehler-     #
 * # meldung LUT2_NO_SLOT_FREE zurückgegeben, aber nichts geschrieben.         #
 * # Vor dem Schreiben wird der Block mittels der ZLIB komprimiert.            #
 * #                                                                           #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>               #
 * #############################################################################
 */

static int write_lut_block_int(FILE *lut,UINT4 typ,UINT4 len,char *data)
{
   char buffer[SLOT_BUFFER],*ptr,*cptr;
   int cnt,slots,i,id,compression_mode;
   UINT4 *lptr;
   unsigned long adler,dir_pos,write_pos;
#if USE_BZIP2>0
   unsigned int compressed_len_bz;
#endif
#if USE_LZO>0
   lzo_uint compressed_len_lzo;
#endif
#if USE_LZMA>0
   size_t compressed_len_lzma=0;
   int retval;
#endif
   unsigned long compressed_len;

   if(!init_status&1)init_atoi_table();
   fseek(lut,0,SEEK_END);  /* Dateiende suchen (Schreibposition für den neuen Block) */
   write_pos=ftell(lut);
   rewind(lut);
   ptr=fgets(buffer,SLOT_BUFFER,lut);
   for(compression_mode=0;ptr && *ptr && strcmp(buffer,"DATA\n");){ /* Inhaltsverzeichnis und Kompression suchen */
      ptr=fgets(buffer,SLOT_BUFFER,lut);
      if(!strcmp(buffer,"Kompression: keine\n"))compression_mode=COMPRESSION_NONE;
      if(!strcmp(buffer,"Kompression: gzip\n"))compression_mode=COMPRESSION_ZLIB;
      if(!strcmp(buffer,"Kompression: bzip2\n"))compression_mode=COMPRESSION_BZIP2;
      if(!strcmp(buffer,"Kompression: lzo\n"))compression_mode=COMPRESSION_LZO;
      if(!strcmp(buffer,"Kompression: lzma\n"))compression_mode=COMPRESSION_LZMA;
   }
   if(!ptr || !*ptr)RETURN(INVALID_LUT_FILE); /* DATA Markierung nicht gefunden */
   if(!compression_mode)compression_mode=COMPRESSION_DEFAULT;
   slots=fgetc(lut)&0xff;
   slots+=fgetc(lut)<<8;
   dir_pos=ftell(lut);     /* Position des Verzeichnisanfangs merken */
   cnt=fread(buffer,12,slots,lut);   /* Verzeichnis komplett einlesen */
   if(cnt!=slots)RETURN(LUT2_FILE_CORRUPTED); /* irgendwas stimmt nicht */
   for(id=-1,i=0,lptr=(UINT4*)buffer;i<slots;i++,lptr+=3){
#if REPLACE_LUT_DIR_ENTRIES>0
         /* Slot mit gleichem Typ oder den nächsten freien Slot suchen */
      if(*lptr==typ || (!*lptr && id<0)){
#else
      if(!*lptr && id<0){   /* den nächsten freien Slot suchen */
#endif
         id=i;
         ptr=(char *)lptr;
      }
   }
   if(id>=0){  /* es wurde einer gefunden */
      if(compression_mode==COMPRESSION_NONE){
         compressed_len=len;
         cptr=data;
      }
      else{
#if COMPRESS==0
         RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#else
         /* Daten komprimieren */
         compressed_len=len+len/100+1024;  /* maximaler Speicherplatz für die komprimierten Daten, großzügig bemessen */
         if(!(cptr=(char *)malloc(compressed_len)))RETURN(ERROR_MALLOC);
         if(compression_mode==COMPRESSION_BZIP2){
#if USE_BZIP2>0
            compressed_len_bz=(unsigned int)compressed_len;
            if(BZ2_bzBuffToBuffCompress(cptr,&compressed_len_bz,data,(unsigned int)len,5,0,0)!=BZ_OK)RETURN(LUT2_COMPRESS_ERROR);
            compressed_len=compressed_len_bz;
#else
            RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#endif
         }
         if(compression_mode==COMPRESSION_LZO){
#if USE_LZO>0
            compressed_len_lzo=(unsigned int)compressed_len;
            if(lzo1x_1_compress(UCP data,(lzo_uint)len,UCP cptr,&compressed_len_lzo,wrkmem)!=LZO_E_OK)RETURN(LUT2_COMPRESS_ERROR);
            compressed_len=compressed_len_lzo;
#endif
         }
         if(compression_mode==COMPRESSION_LZMA){
#if USE_LZMA>0
            if((retval=lzma_easy_buffer_encode(9,LZMA_CHECK_CRC32,NULL,(uint8_t*)data,len,(uint8_t*)cptr,&compressed_len_lzma,compressed_len))!=LZMA_OK)RETURN(LUT2_COMPRESS_ERROR);
            compressed_len=compressed_len_lzma;
#endif
         }
         if(compression_mode==COMPRESSION_ZLIB){
            if(compress2(UCP cptr,ULP &compressed_len,UCP data,len,9)!=Z_OK)RETURN(LUT2_COMPRESS_ERROR);
         }
#endif
      }
      adler=adler32a(1,data,len);
      UL2C(typ,ptr);                   /* Verzeichniseintrag generieren */
      UL2C(write_pos,ptr);
      UL2C(compressed_len,ptr);
      fseek(lut,dir_pos,SEEK_SET);     /* und in die Datei schreiben */
      if(fwrite(buffer,12,slots,lut)<(size_t)slots){
         PRINT_VERBOSE_DEBUG_FILE("fwrite");
         RETURN(FILE_WRITE_ERROR);
      }
      fseek(lut,write_pos,SEEK_SET);   /* Schreibposition auf das Dateiende (Blockdaten) */

         /* kurzer Header vor den Daten: Typ, Länge (komprimiert), Länge (unkomprimiert), Adler32 Prüfsumme */
      ptr=buffer;
      UL2C(typ,ptr);
      UL2C(compressed_len,ptr);
      UL2C(len,ptr);
      UL2C(adler,ptr);
      if(fwrite(buffer,1,16,lut)<16){  /* Prolog des Blocks schreiben */
         PRINT_VERBOSE_DEBUG_FILE("fwrite");
         RETURN(FILE_WRITE_ERROR);
      }
      if(fwrite(cptr,1,compressed_len,lut)<compressed_len){  /* Blockdaten schreiben */
         PRINT_VERBOSE_DEBUG_FILE("fwrite");
         RETURN(FILE_WRITE_ERROR);
      }
      fflush(lut);
#if COMPRESS>0
      if(compression_mode!=COMPRESSION_NONE)FREE(cptr);
#endif
      return OK;
   }
   RETURN(LUT2_NO_SLOT_FREE);
}

/* Funktion read_lut_block() +§§§1 */
/* ###########################################################################
 * # Diese Funktion gehört zum Low-Level-Interface der LUT2-Routinen. Sie    #
 * # liest einen Datenblock aus einer LUT-Datei und gibt die Blocklänge      #
 * # und die Daten by reference (in den Variablen blocklen und data) wieder  #
 * # zurück. Rückgabe ist OK oder ein Fehlercode. Falls in der LUT-Datei     #
 * # mehrere Blocks des angegebenen Typs enthalten sind, wird der letze      #
 * # zurückgeliefert.                                                        #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int read_lut_block(char *lutname, UINT4 typ,UINT4 *blocklen,char **data)
{
   int retval;
   FILE *lut;

   if(!(lut=fopen(lutname,"rb")))RETURN(FILE_READ_ERROR);
   retval=read_lut_block_int(lut,0,typ,blocklen,data);
   fclose(lut);
   RETURN(retval);
}

/* Funktion read_lut_slot() +§§§1 */
/* ###########################################################################
 * # Diese Funktion ähnelt der Funktion read_lut_block(), nur wird ein       #
 * # bestimmter Slot gelesen. So können bei LUT-Dateien, in denen mehrere    #
 * # Blocks eines bestimmeten Typs enthalten sind, auch alte Blocks gelesen  #
 * # werden.                                                                 #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int read_lut_slot(char *lutname,int slot,UINT4 *blocklen,char **data)
{
   int retval;
   FILE *lut;

   if(!(lut=fopen(lutname,"rb")))RETURN(FILE_READ_ERROR);
   retval=read_lut_block_int(lut,slot,0,blocklen,data);
   fclose(lut);
   RETURN(retval);
}

/* Funktion read_lut_block_int() +§§§1 */
/* ###########################################################################
 * # Dies ist eine interne Funktion um einen Block aus einer LUT-Datei zu    #
 * # lesen; sie wird von vielen internen Funktionen benutzt. Die LUT-Datei   #
 * # wird als FILE-Pointer übergeben und nicht geschlossen.                  #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int read_lut_block_int(FILE *lut,int slot,int typ,UINT4 *blocklen,char **data)
{
   char buffer[SLOT_BUFFER],*ptr,*sbuffer,*dbuffer;
   int cnt,slots,i,retval,typ2;
   UINT4 adler,adler2;
   unsigned long read_pos,compressed_len1=0,compression_mode;
#if USE_BZIP2>0
   unsigned int len_bz,compressed_len_bz;
#endif
#if USE_LZO>0
   lzo_uint len_lzo;
#endif
#if USE_LZMA>0
   uint64_t memlimit;
   size_t in_pos,out_pos;

#endif
   unsigned long len,compressed_len;

   if(!init_status&1)init_atoi_table();
   *data=NULL;
   if(blocklen)*blocklen=0;
   rewind(lut);
   ptr=fgets(buffer,SLOT_BUFFER,lut);
   if(!strncmp(buffer,"BLZ Lookup Table/Format 1.",26))RETURN(LUT1_FILE_USED);
   for(compression_mode=0;*ptr && strcmp(buffer,"DATA\n");){ /* Inhaltsverzeichnis und Kompression suchen */
      ptr=fgets(buffer,SLOT_BUFFER,lut);
      if(!strcmp(buffer,"Kompression: keine\n"))compression_mode=COMPRESSION_NONE;  /* keine Kompression */
      if(!strcmp(buffer,"Kompression: gzip\n"))compression_mode=COMPRESSION_ZLIB;  /* Kompression: gzip */
      if(!strcmp(buffer,"Kompression: bzip2\n"))compression_mode=COMPRESSION_BZIP2;  /* Kompression: mit bzip2 */
      if(!strcmp(buffer,"Kompression: lzo\n"))compression_mode=COMPRESSION_LZO;  /* Kompression: mit lzo */
      if(!strcmp(buffer,"Kompression: lzma\n"))compression_mode=COMPRESSION_LZMA;  /* Kompression: mit lzma */
   }
   if(!compression_mode)compression_mode=COMPRESSION_DEFAULT;
   slots=fgetc(lut)&0xff;
   slots+=fgetc(lut)<<8;
   cnt=fread(buffer,12,slots,lut);   /* Verzeichnis komplett einlesen */
   if(cnt!=slots)RETURN(LUT2_FILE_CORRUPTED);   /* irgendwas stimmt nicht */
   if(slot>0 && slot<=slots){ /* einen bestimmten Slot aus der Datei lesen */
      ptr+=(slot-1)*12;
      C2UL(typ,ptr);
      C2UL(read_pos,ptr);
      C2UL(compressed_len1,ptr);
   }
   else for(i=read_pos=0;i<slots;i++){
      C2UL(typ2,ptr);
      if(typ2==typ){ /* gesuchten Typ gefunden; Blockposition und Größe holen */
         C2UL(read_pos,ptr);
         C2UL(compressed_len1,ptr);
      }
      else
         ptr+=8;
   }
   if(read_pos){
      fseek(lut,read_pos,SEEK_SET);
      if(fread(buffer,1,16,lut)<16)RETURN(FILE_READ_ERROR); /* Blockheader lesen */
      ptr=buffer;
      C2UL(typ2,ptr);
      if(typ2!=typ)RETURN(LUT2_FILE_CORRUPTED);
      C2UL(compressed_len,ptr);
      if(compressed_len!=compressed_len1)RETURN(LUT2_FILE_CORRUPTED);
      C2UL(len,ptr);
      C2UL(adler,ptr);

         /* für den Block wird etwas mehr Speicher allokiert als eigentlich
          * notwendig wäre, um nachher z.B. bei Textblocks noch ein Nullbyte in
          * den Block schreiben zu können.
         */
      if(compression_mode==COMPRESSION_NONE){
         if(!(dbuffer=(char *)malloc(len+10)))RETURN(ERROR_MALLOC);
         if(fread(dbuffer,1,len,lut)<len)RETURN(FILE_READ_ERROR);
         adler2=adler32a(1,dbuffer,len);
         if(adler!=adler2){
            FREE(dbuffer);
            RETURN(LUT_CRC_ERROR);
         }
         if(blocklen)*blocklen=len;
         *data=dbuffer;
         return OK;
      }
      else{
#if COMPRESS==0
         RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#else
         if(!(sbuffer=(char *)malloc(compressed_len+10)))RETURN(ERROR_MALLOC);
        if(!(dbuffer=(char *)malloc(len+10))){
            FREE(sbuffer);
            RETURN(ERROR_MALLOC);
         }

         if(fread(sbuffer,1,compressed_len,lut)<compressed_len){
            FREE(sbuffer);
            FREE(dbuffer);
            RETURN(FILE_READ_ERROR);;
         }
         retval=Z_DATA_ERROR; /* Vorsichtsmaßnahme für unbekannte Kompressions-Bibliothek */
         if(compression_mode==COMPRESSION_BZIP2){
#if USE_BZIP2>0
            len_bz=(unsigned int)len;
            compressed_len_bz=(unsigned int)compressed_len;
            retval=BZ2_bzBuffToBuffDecompress(dbuffer,&len_bz,sbuffer,(unsigned int)compressed_len_bz,0,0);
            len=len_bz;
#else
            FREE(sbuffer);
            FREE(dbuffer);
            RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#endif
         }
         if(compression_mode==COMPRESSION_LZO){
#if USE_LZO>0
            len_lzo=(lzo_uint)len;
            retval=lzo1x_decompress(UCP sbuffer,(lzo_uint)compressed_len,UCP dbuffer,&len_lzo,NULL);
            len=len_lzo;
#else
            FREE(sbuffer);
            FREE(dbuffer);
            FREE(own_buffer);
            RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#endif
         }
         if(compression_mode==COMPRESSION_LZMA){
#if USE_LZMA>0
            memlimit=70000000;
            in_pos=out_pos=0;
            retval=lzma_stream_buffer_decode(&memlimit,0,NULL,(uint8_t*)sbuffer,&in_pos,
                  (size_t)compressed_len,(uint8_t*)dbuffer,&out_pos,len);
            len=out_pos;
#else
            FREE(sbuffer);
            FREE(dbuffer);
            RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#endif
         }
         if(compression_mode==COMPRESSION_ZLIB)
            retval=uncompress(UCP dbuffer,ULP &len,UCP sbuffer,compressed_len);
         FREE(sbuffer);
         adler2=adler32a(1,dbuffer,len);
         if(adler!=adler2 && retval==Z_OK)retval=LUT_CRC_ERROR;
         if(retval!=Z_OK)FREE(dbuffer);
         if(compression_mode==COMPRESSION_ZLIB)switch(retval){
            case Z_OK:
               if(blocklen)*blocklen=len;
               *data=dbuffer;
               return OK;
            case Z_BUF_ERROR:
               RETURN(LUT2_Z_BUF_ERROR);
            case Z_MEM_ERROR:
               RETURN(LUT2_Z_MEM_ERROR);
            case Z_DATA_ERROR:
               RETURN(LUT2_Z_DATA_ERROR);
            default:
               RETURN(retval);
         }
#if USE_BZIP2>0
         if(compression_mode==COMPRESSION_BZIP2)switch(retval){
            case BZ_RUN_OK:
            case BZ_FLUSH_OK:
            case BZ_FINISH_OK:
            case BZ_STREAM_END:
            case BZ_OK:
               if(blocklen)*blocklen=len;
               *data=dbuffer;
               return OK;

            case BZ_OUTBUFF_FULL:
            case BZ_CONFIG_ERROR:
               RETURN(LUT2_Z_BUF_ERROR);

            case BZ_MEM_ERROR:
               RETURN(LUT2_Z_MEM_ERROR);

            case BZ_SEQUENCE_ERROR:
            case BZ_PARAM_ERROR:
            case BZ_DATA_ERROR:
            case BZ_DATA_ERROR_MAGIC:
            case BZ_IO_ERROR:
            case BZ_UNEXPECTED_EOF:
               RETURN(LUT2_Z_DATA_ERROR);
            default:
               RETURN(retval);
         }
#endif
#if USE_LZO>0
         if(compression_mode==COMPRESSION_LZO)switch(retval){
            case LZO_E_OK:
               if(blocklen)*blocklen=len;
               *data=dbuffer;
               return OK;

            case LZO_E_INPUT_OVERRUN:
               RETURN(LUT2_Z_BUF_ERROR);

            case LZO_E_LOOKBEHIND_OVERRUN:
            case LZO_E_OUTPUT_OVERRUN:
               RETURN(LUT2_Z_MEM_ERROR);

            case LZO_E_INPUT_NOT_CONSUMED:
            case LZO_E_ERROR:
            case LZO_E_EOF_NOT_FOUND:
               RETURN(LUT2_Z_DATA_ERROR);

            default:
               RETURN(retval);
         }
#endif
#if USE_LZMA>0
         if(compression_mode==COMPRESSION_LZMA)switch(retval){
            case LZMA_OK:
               if(blocklen)*blocklen=len;
               *data=dbuffer;
               return OK;


            case LZMA_BUF_ERROR:
               RETURN(LUT2_Z_BUF_ERROR);

            case LZMA_MEMLIMIT_ERROR:
               fprintf(stderr,"Memlimit Fehler; Minimalwert für memlimit ist %llu\n",memlimit);
               RETURN(LUT2_Z_MEM_ERROR);

            case LZMA_MEM_ERROR:
               RETURN(LUT2_Z_MEM_ERROR);

            case LZMA_FORMAT_ERROR:
            case LZMA_OPTIONS_ERROR:
            case LZMA_DATA_ERROR:
               RETURN(LUT2_Z_DATA_ERROR);

            default:
               RETURN(retval);
         }
#endif
#endif
      }
   }
   RETURN(LUT2_BLOCK_NOT_IN_FILE);
}

/* Funktion lut_dir() +§§§1 */
/* #############################################################################
 * # Dies ist eine interne Funktion, die das Verzeichnis einer LUT-Datei       #
 * # einliest und in den Variablen slot_cnt die Gesamtzahl der Slots in der    #
 * # Datei sowie in slot_dir das aktuelle Verzeichnis (Blocktyp zu jedem Slot) #
 * # zurückliefert. Die Variable slot_dir muß auf ein Integerarray zeigen,     #
 * # das groß genug ist, um alle Einträge aufzunehmen; die Funktion allokiert  #
 * # keinen Speicher.                                                          #
 * #                                                                           #
 * # Falls in der Variablen id ein Wert>0 übergeben wird, wird der Slot mit    #
 * # dieser Nummer (nicht Typ!!) gelesen und getestet; in typ, len,            #
 * # compressed_len sowie adler werden die entsprechenden Werte zurück-        #
 * # gegeben. Falls eine Variable nicht benötigt wird, kann für sie auch       #
 * # NULL übergeben werden; die entsprechende Variable wird dann ignoriert.    #
 * #                                                                           #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>               #
 * #############################################################################
 */

static int lut_dir(FILE *lut,int id,UINT4 *slot_cnt,UINT4 *typ,UINT4 *len,
      UINT4 *compressed_len,UINT4 *adler,int *slot_dir,int *compression)
{
   char buffer[SLOT_BUFFER],*ptr,*sbuffer,*dbuffer;
   int i,cnt,slots,retval,typ1,typ2,compression_mode;
   unsigned long read_pos,compressed_len2,adler1,adler2;
   unsigned long len1,compressed_len1;

#if USE_BZIP2>0
   unsigned int len1_bz;
#endif

#if USE_LZO>0
   lzo_uint len1_lzo;
#endif

#if USE_LZMA>0
   uint64_t memlimit;
   size_t in_pos,out_pos;
#endif

      /* Rückgabevariablen initialisieren */
   if(slot_cnt)*slot_cnt=0;
   if(typ)*typ=0;
   if(len)*len=0;
   if(compressed_len)*compressed_len=0;
   if(adler)*adler=0;
   if(!init_status&1)init_atoi_table();

      /* Inhaltsverzeichnis suchen, testen ob LUT2 Datei */
   rewind(lut);
   ptr=fgets(buffer,SLOT_BUFFER,lut);
   while(*ptr && *ptr!='\n')ptr++;
   *--ptr=0;
   if(!strcmp(buffer,"BLZ Lookup Table/Format 1."))RETURN(LUT1_FILE_USED); /* alte LUT-Datei */
   if(strcmp(buffer,"BLZ Lookup Table/Format 2."))RETURN(INVALID_LUT_FILE); /* keine LUT-Datei */

   compression_mode=0;
   do{
      ptr=fgets(buffer,SLOT_BUFFER,lut);
      if(!strcmp(buffer,"Kompression: keine\n"))compression_mode=COMPRESSION_NONE;  /* keine Kompression */
      if(!strcmp(buffer,"Kompression: gzip\n"))compression_mode=COMPRESSION_ZLIB;  /* Kompression: gzip */
      if(!strcmp(buffer,"Kompression: bzip2\n"))compression_mode=COMPRESSION_BZIP2;  /* Kompression: mit bzip2 */
      if(!strcmp(buffer,"Kompression: lzo\n"))compression_mode=COMPRESSION_LZO;  /* Kompression: mit bzip2 */
      if(!strcmp(buffer,"Kompression: lzma\n"))compression_mode=COMPRESSION_LZMA;  /* Kompression: mit bzip2 */
   }while(*ptr && strcmp(buffer,"DATA\n"));
   if(!compression_mode)compression_mode=COMPRESSION_DEFAULT;
   if(compression)*compression=compression_mode;
   slots=fgetc(lut)&0xff;  /* Anzahl Slots holen */
   slots+=fgetc(lut)<<8;
   cnt=fread(buffer,12,slots,lut);   /* Verzeichnis komplett einlesen */
   if(cnt!=slots)RETURN(LUT2_FILE_CORRUPTED);   /* irgendwas stimmt nicht */
   if(slot_cnt)*slot_cnt=slots;
   if(slot_dir)for(i=0,ptr=buffer;i<slots;i++,ptr+=8)C2UL(slot_dir[i],ptr);
   if(id<1)return OK;
   ptr=buffer+(id-1)*12;
   C2UL(typ1,ptr);
   C2UL(read_pos,ptr);
   C2UL(compressed_len1,ptr);
   if(id>slots || typ1==0)return OK;
   fseek(lut,read_pos,SEEK_SET);
   if(fread(buffer,1,16,lut)<16)RETURN(FILE_READ_ERROR); /* Blockheader lesen und testen */
   ptr=buffer;
   C2UL(typ2,ptr);
   if(typ2!=typ1)RETURN(LUT2_FILE_CORRUPTED);
   C2UL(compressed_len2,ptr);
   if(compressed_len2!=compressed_len1)RETURN(LUT2_FILE_CORRUPTED);
   C2UL(len1,ptr);
   C2UL(adler1,ptr);
   if(!adler){
      if(typ)*typ=typ1;
      if(len)*len=len1;
      if(compressed_len)*compressed_len=compressed_len1;
      return OK;
   }
   if(compression_mode==COMPRESSION_NONE){
      if(!(sbuffer=(char *)malloc(compressed_len1)))RETURN(ERROR_MALLOC);
      if(fread(sbuffer,1,compressed_len1,lut)<compressed_len1)RETURN(FILE_READ_ERROR);
      adler2=adler32a(1,sbuffer,len1);
      FREE(sbuffer);
      if(adler1!=adler2)RETURN(LUT_CRC_ERROR);
   }
   else{
#if COMPRESS==0
      RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#else
      if(!(sbuffer=(char *)malloc(compressed_len1)) || !(dbuffer=(char *)malloc(len1)))RETURN(ERROR_MALLOC);
      if(fread(sbuffer,1,compressed_len1,lut)<compressed_len1)RETURN(FILE_READ_ERROR);
      retval=Z_DATA_ERROR; /* Vorsichtsmaßnahme für unbekannte Kompressions-Bibliothek */
      if(compression_mode==COMPRESSION_BZIP2){
#if USE_BZIP2>0
         len1_bz=(unsigned int)len1;
         retval=BZ2_bzBuffToBuffDecompress(dbuffer,&len1_bz,sbuffer,(unsigned int)compressed_len1,0,0);
         len1=len1_bz;
#else
         FREE(sbuffer);
         FREE(dbuffer);
         RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#endif
      }
      if(compression_mode==COMPRESSION_LZO){
#if USE_LZO>0
         len1_lzo=(lzo_uint)len1;
         retval=lzo1x_decompress(UCP sbuffer,(lzo_uint)compressed_len1,UCP dbuffer,&len1_lzo,NULL);
         len1=len1_lzo;
#else
         FREE(sbuffer);
         FREE(dbuffer);
         RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#endif
      }
      if(compression_mode==COMPRESSION_LZMA){
#if USE_LZMA>0
         memlimit=70000000;
         in_pos=out_pos=0;
         retval=lzma_stream_buffer_decode(&memlimit,0,NULL,(uint8_t*)sbuffer,&in_pos,
               (size_t)compressed_len1,(uint8_t*)dbuffer,&out_pos,len1);
         if(retval==LZMA_MEMLIMIT_ERROR){
            fprintf(stderr,"Memlimit Fehler; Minimalwert für memlimit ist %llu\n",memlimit);
            RETURN(LUT2_Z_MEM_ERROR);
         }
         len1=out_pos;
#else
         FREE(sbuffer);
         FREE(dbuffer);
         RETURN(KTO_CHECK_UNSUPPORTED_COMPRESSION);
#endif
      }
      if(compression_mode==COMPRESSION_ZLIB)
         retval=uncompress(UCP dbuffer,ULP &len1,UCP sbuffer,compressed_len1);
      FREE(sbuffer);
      adler2=adler32a(1,dbuffer,len1);
      FREE(dbuffer);
      if(adler1!=adler2)RETURN(LUT_CRC_ERROR);
      switch(retval){
#if USE_BZIP2>0
         case BZ_OUTBUFF_FULL:
            RETURN(LUT2_Z_MEM_ERROR);
#endif
         case Z_OK: 
            break;
         case Z_BUF_ERROR:
         case Z_MEM_ERROR:
            RETURN(LUT2_Z_MEM_ERROR);
         case Z_DATA_ERROR:
            RETURN(LUT2_Z_DATA_ERROR);
         default:
            RETURN(LUT2_DECOMPRESS_ERROR);
      }
#endif
   }
   if(typ)*typ=typ1;
   if(len)*len=len1;
   if(compressed_len)*compressed_len=compressed_len1;
   if(adler)*adler=adler1;
   return OK;
}

/* @@ Funktion write_lutfile_entry_de() +§§§1 */
/* ###########################################################################
 * # Diese Funktion schreibt einen Datenblock in die LUT-Datei. Die Rohdaten #
 * # werden aus dem jeweiligen Array geholt und in einen Buffer geschrieben; #
 * # dieser Buffer wird dann mittels der Funktion write_lut_block_int()      #
 * # komprimiert und in die LUT-Datei geschrieben.                           #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int write_lutfile_entry_de(UINT4 typ,int auch_filialen,int bank_cnt,char *out_buffer,
      FILE *lut,UINT4 set,int add_idx)
{
   char *ptr,*zptr,*bptr,*dptr,*name_hauptstelle=NULL,*name_start=NULL,*data,*data_idx,**sortc_buf1,**sortc_buf2;
   int cnt,i,j,k,max,b,prev_blz,diff,hs,retval,qs_hs,*iptr;

   if(set==2)typ+=SET_OFFSET;  /* sekundäres Set schreiben */

      /* in out_buffer steht ein buffer für die Ausgabesachen bereit. Er ist so
       * groß wie die BLZ-Datei der Bundesbank, hat also genügend Luft für alle
       * Blocks im Klartext sowie noch zusätzlich die Index-Arrays und die
       * Pointer auf die String-Daten. Diese beiden Arrays werden am Beginn von
       * out_buffer plaziert, da sie eine feste Größe haben; danach kommt der
       * Buffer data für die Blockdaten (Rohwerte) sowie data_idx (später, erst
       * bei der Index-Generierung) für die Indexdaten.
       */
   iptr=(int*)out_buffer;
   sortc_buf1=(char**)(iptr+(bank_cnt+10));
   sorti_buf=(int*)sortc_buf1;
   sortc_buf2=(char**)(sortc_buf1+(bank_cnt+10));
   data=(char*)(sortc_buf2+(bank_cnt+10));

   switch(typ){
      case LUT2_BLZ:  /* Bankleitzahl */
      case LUT2_2_BLZ:
            /* die Anzahl der Hauptstellen wird erst nach der Schleife
             * eingetragen, da sie hier noch nicht bekannt ist. Die Ausgabe
             * beginnt daher erst bei data+4.
             *
             * Die innere Struktur des BLZ-Blocks entspricht dem der
             * Lut-Versionen 1.0/1.1, allerdings wird der Block noch
             * komprimiert und dadurch etwas kleiner. Die Bankleitzahlen sind
             * sortiert und innerhalb derselben BLZ so angeordnet, daß jeweils
             * die Hauptstelle als erste erscheint.
             */
         for(i=cnt=prev_blz=0,dptr=data+4;i<bank_cnt;i++){
            zptr=qs_zeilen[qs_sortidx[i]];
            b=qs_blz[qs_sortidx[i]];
            diff=b-prev_blz;
            prev_blz=b;
            if(diff==0) /* gleiche Bank (Zweigstelle), kein Eintrag */
               continue;
            else if(diff>0 && diff<=253){
               *dptr++=diff&255;
            }
            else if(diff>253 && diff<65536){   /* 2 Byte, Kennmarker 254 */
               *dptr++=254;
               UI2C(diff,dptr);
            }
            else if(diff>65535){   /* Wert direkt eintragen, Kennmarker 255 */
               *dptr++=255;
               UL2C(b,dptr);
            }
            cnt++;
         }
         ptr=data;
         UI2C(cnt,ptr);       /* Anzahl Hauptstellen an den Anfang schreiben */
         UI2C(bank_cnt,ptr);  /* Anzahl Datensätze (mit Nebenstellen) */
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));
         break;

      case LUT2_FILIALEN:  /* Anzahl Filialen */
      case LUT2_2_FILIALEN:
         if(auch_filialen){
            for(i=max=1,cnt=1,j=10000000,dptr=data;i<bank_cnt;i++){
               if(j==qs_blz[qs_sortidx[i]])
                  cnt++;
               else{
                  *dptr++=cnt&255;
                  if(cnt>max)max=cnt;
                  cnt=1;
                  j=qs_blz[qs_sortidx[i]];
               }
            }
            *dptr++=cnt&255;
            if(cnt>240){
               fprintf(stderr,"maximale Anzahl bei Filialen: %d\n",max);
               if(cnt>255)fprintf(stderr,"Fehler in LUT-Datei wegen Maximalzahl>255!!\n");
            }
            CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));
         }
         break;

      case LUT2_NAME:  /* Bezeichnung des Kreditinstitutes (ohne Rechtsform) */
      case LUT2_2_NAME:
         for(i=j=0,name_hauptstelle=name_start=(char*)"",dptr=data;i<bank_cnt;i++)
            if((hs=qs_hauptstelle[qs_sortidx[i]])=='1' || auch_filialen){
               zptr=qs_zeilen[qs_sortidx[i]];
               if(hs=='1' && auch_filialen){
                  *dptr++=1;  /* Markierung für Hauptstelle, kann im Text nicht vorkommen */
                  sortc_buf1[j]=name_hauptstelle=dptr;
               }
               else
                  sortc_buf1[j]=name_start=dptr;
               for(ptr=zptr+9;ptr<zptr+67;)*dptr++=*ptr++;
               if(*(dptr-1)==' '){
                  for(dptr--;*dptr==' ';)dptr--;
                  dptr++;  /* das letzte Byte war kein Blank mehr */
               }
               *dptr++=0;
                  /* falls der Name einer Nebenstelle dem der Hauptstelle entspricht, nur ein Nullbyte eintragen */
               if(hs=='2' && !strcmp(name_hauptstelle,name_start)){
                  dptr=name_start;
                  *dptr++=0;
                  sortc_buf1[j]=name_hauptstelle;
               }
               j++;
            }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));

            /* Index-Block für Namen generieren */
         if(add_idx){
            data_idx=dptr;
            sortc_buf=sortc_buf1;
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sortc);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_NAME_SORT+(typ-LUT2_NAME),dptr-data_idx,data_idx));
         }
         break;

      case LUT2_NAME_NAME_KURZ:  /* Name und Kurzname zusammen => besser (72212 Byte kompr. gegenüber 85285 bei getrennt) */
      case LUT2_2_NAME_NAME_KURZ:
         for(i=j=0,dptr=data;i<bank_cnt;i++)if((hs=qs_hauptstelle[qs_sortidx[i]])=='1' || auch_filialen){
            zptr=qs_zeilen[qs_sortidx[i]];

               /* Bankname */
            if(hs=='1' && auch_filialen){
               *dptr++=1;  /* Markierung für Hauptstelle, kann im Text nicht vorkommen */
               sortc_buf1[j]=name_hauptstelle=dptr;
            }
            else
               sortc_buf1[j]=name_start=dptr;
            for(ptr=zptr+9;ptr<zptr+67;)*dptr++=*ptr++;
            if(*(dptr-1)==' '){
               for(dptr--;*dptr==' ';)dptr--;
               dptr++;  /* das letzte Byte war kein Blank mehr */
            }
            *dptr++=0;
               /* falls der Name einer Nebenstelle dem der Hauptstelle entspricht, nur ein Nullbyte eintragen */
            if(hs=='2' && !strcmp(name_hauptstelle,name_start)){
               dptr=name_start;
               *dptr++=0;
               sortc_buf1[j]=name_hauptstelle;
            }

               /* Kurzbezeichnung */
            for(ptr=zptr+107,sortc_buf2[j]=dptr;ptr<zptr+134;)*dptr++=*ptr++;
            if(*(dptr-1)==' '){
               for(dptr--;*dptr==' ';)dptr--;
               dptr++;  /* das letzte Byte war kein Blank mehr */
            }
            *dptr++=0;
            j++;
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));

            /* Index-Block für Namen und Kurznamen generieren */
         if(add_idx){
            data_idx=dptr;
            sortc_buf=sortc_buf1;   /* Namen */
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sortc);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_NAME_SORT+(typ-LUT2_NAME_NAME_KURZ),dptr-data_idx,data_idx));

               /* Index-Block für Kurznamen generieren */
            sortc_buf=sortc_buf2;   /* Kurznamen */
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sortc);
            dptr=data_idx;
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_NAME_KURZ_SORT+(typ-LUT2_NAME_NAME_KURZ),dptr-data_idx,data_idx));
         }
         break;

      case LUT2_PLZ:  /* Postleitzahl */
      case LUT2_2_PLZ:
         for(i=j=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            k=Z(b5,67)+Z(b4,68)+Z(b3,69)+Z(b2,70)+Z(b1,71);
            UM2C(k,dptr);
            sorti_buf[j++]=k;
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));

            /* Index-Block für PLZ generieren */
         if(add_idx){
            data_idx=dptr;
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sorti);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_PLZ_SORT+(typ-LUT2_PLZ),dptr-data_idx,data_idx));
         }
         break;

      case LUT2_ORT:  /* Ort */
      case LUT2_2_ORT:
         for(i=j=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            for(ptr=zptr+72,sortc_buf1[j]=dptr;ptr<zptr+107;)*dptr++=*ptr++;
            if(*(dptr-1)==' '){
               for(dptr--;*dptr==' ';)dptr--;
               dptr++;  /* das letzte Byte war kein Blank mehr */
            }
            *dptr++=0;
            j++;
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));

            /* Index-Block für Ort generieren */
         if(add_idx){
            data_idx=dptr;
            sortc_buf=sortc_buf1;
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sortc);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_ORT_SORT+(typ-LUT2_ORT),dptr-data_idx,data_idx));
         }
         break;

      case LUT2_NAME_KURZ:  /* Kurzbezeichnung des Kreditinstitutes mit Ort (ohne Rechtsform) */
      case LUT2_2_NAME_KURZ:
         for(i=j=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            for(ptr=zptr+107,sortc_buf1[j]=dptr;ptr<zptr+134;)*dptr++=*ptr++;
            if(*(dptr-1)==' '){
               for(dptr--;*dptr==' ';)dptr--;
               dptr++;  /* das letzte Byte war kein Blank mehr */
            }
            *dptr++=0;
            j++;
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));

            /* Index-Block für Kurznamen generieren */
         if(add_idx){
            data_idx=dptr;
            sortc_buf=sortc_buf1;
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sortc);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_NAME_KURZ_SORT+(typ-LUT2_NAME_KURZ),dptr-data_idx,data_idx));
         }
         break;

      case LUT2_PAN:  /* Institutsnummer für PAN */
      case LUT2_2_PAN:
         for(i=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            if(*(zptr+134)==' ' && *(zptr+135)==' ' && *(zptr+136)==' ' && *(zptr+137)==' ' && *(zptr+138)==' ')
               k=0;
            else
               k=Z(b5,134)+Z(b4,135)+Z(b3,136)+Z(b2,137)+Z(b1,138);
            UM2C(k,dptr);
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));
         break;

      case LUT2_BIC:  /* Bank Identifier Code - BIC */
      case LUT2_2_BIC:
         for(i=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];

               /* BIC mit DE an Stellen 5 und 6 (normal): die beiden Stellen weglassen */
            if(*(zptr+139)!=' ' && *(zptr+143)=='D' && *(zptr+144)=='E'){
               ptr=zptr+139;
               *dptr++=*ptr++;
               *dptr++=*ptr++;
               *dptr++=*ptr++;
               *dptr++=*ptr++;
               ptr+=2;  /* Stellen mit DE überspringen */
               *dptr++=*ptr++;
               *dptr++=*ptr++;
               *dptr++=*ptr++;
               *dptr++=*ptr++;
               *dptr++=*ptr;
            }

               /* BIC mit anderem Länderkennzeichen: Marker 1 an erster Stelle
                * schreiben. (Dies kann normal nicht vorkommen, da nur
                * Buchstaben und Zahlen erlaubt sind, und ist somit sicher) */
            else if(*(zptr+139)!=' '){
               *dptr++=1;  /* Flag für Landkennzeichen != DE, 11 Stellen schreiben */
               for(ptr=zptr+139;ptr<zptr+150;)*dptr++=*ptr++;
            }

               /* kein BIC: nur ein Nullbyte schreiben */
            else
               *dptr++=0;
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));

            /* Index-Block für BIC generieren. Die BICs werden noch einmal neu
             * eingelesen, da sich die obige Version nicht zum Sortieren eignet.
            */
         if(add_idx){
            for(i=j=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
               zptr=qs_zeilen[qs_sortidx[i]];
               sortc_buf1[j++]=dptr;
               if(*(zptr+139)!=' ')for(ptr=zptr+139;ptr<zptr+150;)*dptr++=*ptr++;
               *dptr++=0;
            }
            data_idx=dptr;
            sortc_buf=sortc_buf1;
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sortc);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_BIC_SORT+(typ-LUT2_BIC),dptr-data_idx,data_idx));

               /* nun nochmal fast dasselbe, nur die BICs der Nebenstellen mit denen der Hauptstelle füllen */
            for(i=j=0,bptr=dptr=data;i<bank_cnt;i++){
               qs_hs=qs_hauptstelle[qs_sortidx[i]]=='1'?1:0;   /* Kennzeichen Haupt/Nebenstelle */
               if(auch_filialen || qs_hs){
                  zptr=qs_zeilen[qs_sortidx[i]];
                  sortc_buf1[j++]=dptr;
                  if(qs_hs) /* Hauptstelle */
                     for(bptr=ptr=zptr+139;ptr<zptr+150;)*dptr++=*ptr++;
                  else  /* Nebenstelle */
                     /* bptr wird bei der vorhergehenden HS gesetzt, die kommen *immer* vor den Nebenstellen */
                     for(ptr=bptr;ptr<bptr+11;)*dptr++=*ptr++;
                  *dptr++=0;
               }
            }
            data_idx=dptr;
            sortc_buf=sortc_buf1;
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sortc);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_BIC_H_SORT+(typ-LUT2_BIC),dptr-data_idx,data_idx));
         }
         break;

      case LUT2_PZ:  /* Kennzeichen für Prüfzifferberechnungsmethode */
      case LUT2_2_PZ:
            /* Prüfziffermethoden nur für die Hauptstellen und Testbanken */
         for(i=j=0,dptr=data;i<bank_cnt;i++){
            if(qs_hauptstelle[qs_sortidx[i]]=='1' || qs_hauptstelle[qs_sortidx[i]]=='3'){
               zptr=qs_zeilen[qs_sortidx[i]];
               *dptr++=k=bx2[(int)*(zptr+150)]+bx1[(int)*(zptr+151)];
               sorti_buf[j++]=k;
            }
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));

            /* Index-Block für PZ generieren und schreiben */
         if(add_idx){
            data_idx=dptr;
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sorti);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_PZ_SORT+(typ-LUT2_PZ),dptr-data_idx,data_idx));
         }
         break;

      case LUT2_NR:  /* Nummer des Datensatzes */
      case LUT2_2_NR:
         for(i=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            j=Z(b6,152)+Z(b5,153)+Z(b4,154)+Z(b3,155)+Z(b2,156)+Z(b1,157);
            UM2C(j,dptr);
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));
         break;

      case LUT2_AENDERUNG:  /* Änderungskennzeichen */
      case LUT2_2_AENDERUNG:
         for(i=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            *dptr++=*(zptr+158);
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));
         break;

      case LUT2_LOESCHUNG:  /* Hinweis auf eine beabsichtigte Bankleitzahllöschung */
      case LUT2_2_LOESCHUNG:
         for(i=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            *dptr++=*(zptr+159);
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));
         break;

      case LUT2_NACHFOLGE_BLZ:  /* Hinweis auf Nachfolge-Bankleitzahl */
      case LUT2_2_NACHFOLGE_BLZ:
         for(i=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            j=Z(b8,160)+Z(b7,161)+Z(b6,162)+Z(b5,163)+Z(b4,164)+Z(b3,165)+Z(b2,166)+Z(b1,167);
            UL2C(j,dptr);
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));
         break;

      case LUT2_VOLLTEXT_TXT:  /* Volltext-Suchindex: zunächst die Daten sammeln */
      case LUT2_2_VOLLTEXT_TXT:

            /* für die Volltextsuche werden die folgenden Daten aufgenommen:
             *
             *    Name (9...66)
             *    Ort (72...106)
             *    Kurzname (107...133)
             *
             */
         {
            char **vt_ptr,*ptr1;
            int *vt_idx,*vt_bank,cnt,vt_cnt_max,vt_cnt_uniq,vt_buflen_uniq,idx;
            int *vt_array,*vt_cnt_uniq_array,vt_cnt_1,vt_cnt_array,vt_a1;

   /* Initialwert Anzahl Worte; wird per realloc() vergrößert */
#define VT_CNT 100000

            vt_cnt_max=VT_CNT;
            if(!(vt_ptr=(char **)malloc((vt_cnt_max+100)*sizeof(char*))))return ERROR_MALLOC;
            if(!(vt_bank=(int *)malloc((vt_cnt_max+100)*sizeof(int))))return ERROR_MALLOC;
            dptr=data=out_buffer;
            for(*vt_bank=cnt=i=j=0,dptr=*vt_ptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
               if(cnt>vt_cnt_max){
                  vt_cnt_max+=10000;
                  if(!(vt_ptr=(char **)realloc(vt_ptr,(vt_cnt_max+100)*sizeof(char*))))return ERROR_MALLOC;
                  if(!(vt_bank=(int *)realloc(vt_bank,(vt_cnt_max+100)*sizeof(int))))return ERROR_MALLOC;
               }
               zptr=qs_zeilen[qs_sortidx[i]];
               for(ptr=zptr+9;ptr<zptr+67;)
                  if(volltext_zeichen(UCPP &ptr))
                     *dptr++=*ptr++;
                  else{
                     *dptr++=0;
                     if(*vt_ptr[cnt])cnt++;
                     vt_ptr[cnt]=dptr;
                     vt_bank[cnt]=j;
                     while(!volltext_zeichen(UCPP &ptr) && ptr<(zptr+67))ptr++;
                  }
               *dptr++=0;
               if(*vt_ptr[cnt])cnt++;
               vt_ptr[cnt]=dptr;
               vt_bank[cnt]=j;
               for(ptr=zptr+72;ptr<zptr+107;)
                  if(volltext_zeichen(UCPP &ptr))
                     *dptr++=*ptr++;
                  else{
                     *dptr++=0;
                     if(*vt_ptr[cnt])cnt++;
                     vt_ptr[cnt]=dptr;
                     vt_bank[cnt]=j;
                     while(!volltext_zeichen(UCPP &ptr) && ptr<(zptr+107))ptr++;
                  }
               *dptr++=0;
               if(*vt_ptr[cnt])cnt++;
               vt_ptr[cnt]=dptr;
               vt_bank[cnt]=j;
               for(ptr=zptr+107;ptr<zptr+134;)
                  if(volltext_zeichen(UCPP &ptr))
                     *dptr++=*ptr++;
                  else{
                     *dptr++=0;
                     if(*vt_ptr[cnt])cnt++;
                     vt_ptr[cnt]=dptr;
                     vt_bank[cnt]=j;
                     while(!volltext_zeichen(UCPP &ptr) && ptr<(zptr+134))ptr++;
                  }
               *dptr++=0;
               j++;
               if(*vt_ptr[cnt])cnt++;
               vt_ptr[cnt]=dptr;
               vt_bank[cnt]=j;
            }
            *dptr++=0;

            if(!(vt_idx=(int *)malloc((cnt)*sizeof(int))))return ERROR_MALLOC;
            for(i=0;i<cnt;i++)vt_idx[i]=i;
            sortc_buf=vt_ptr;
            qsort(vt_idx,cnt,sizeof(int),qcmp_sortc);
            vt_buflen_uniq=strlen(vt_ptr[vt_idx[0]])+1;
            vt_a1=vt_bank[vt_idx[0]];
            for(i=0,vt_cnt_uniq=1;i<cnt;i++){
               if(!stri_cmp(ptr,vt_ptr[vt_idx[i]])){   /* Dublette Wort */
                  continue;
               }
               ptr=vt_ptr[vt_idx[i]];
               vt_buflen_uniq+=strlen(ptr)+1;
               vt_cnt_uniq++;
               vt_a1=vt_bank[vt_idx[i]];
            }
            if(!(data=dptr=(char *)malloc(vt_buflen_uniq+100)))return ERROR_MALLOC;
            if(!(vt_cnt_uniq_array=(int *)malloc((vt_cnt_uniq+cnt+50)*sizeof(int))))return ERROR_MALLOC;
            vt_array=vt_cnt_uniq_array+vt_cnt_uniq;
            for(ptr=ptr1=vt_ptr[vt_idx[0]];(*dptr++=*ptr1++););
            vt_a1=vt_cnt_1=0;
            for(vt_cnt_array=i=j=0,k=0;i<cnt;i++){
               idx=vt_idx[i];
               if(!stri_cmp(ptr,vt_ptr[idx])){   /* Dublette Wort */
                  if(vt_bank[idx]!=vt_a1){   /* keine Dublette Bank */
                     vt_a1=vt_array[k++]=vt_bank[idx];
                     vt_cnt_1++;
                  }
                  continue;
               }
               vt_cnt_uniq_array[j++]=vt_cnt_1;
               vt_cnt_array+=vt_cnt_1;
               vt_a1=vt_array[k++]=vt_bank[idx];
               vt_cnt_1=1;
               for(ptr=ptr1=vt_ptr[idx];(*dptr++=*ptr1++););
               i--;
            }
            vt_cnt_array+=vt_cnt_1;
            vt_cnt_uniq_array[j]=vt_cnt_1;
            CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));
            free(data); /* Speicher für uniq text */

               /* Index-Block für Volltextsuche generieren */
            dptr=data=out_buffer;
            UL2C(vt_cnt_uniq,dptr);
            UL2C(vt_cnt_array,dptr);
            for(i=0;i<vt_cnt_uniq;i++)UI2C(vt_cnt_uniq_array[i],dptr);
            for(i=0;i<vt_cnt_array;i++)UI2C(vt_array[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_VOLLTEXT_IDX+(typ-LUT2_VOLLTEXT_TXT),dptr-data,data));

            free(vt_idx);
            free(vt_bank);
            free(vt_ptr);
            free(vt_cnt_uniq_array);
         }
         break;

      case LUT2_IBAN_REGEL:  /* IBAN-Regeln */
      case LUT2_2_IBAN_REGEL:
         for(i=j=0,dptr=data;i<bank_cnt;i++)if(auch_filialen || qs_hauptstelle[qs_sortidx[i]]=='1'){
            zptr=qs_zeilen[qs_sortidx[i]];
            k=Z(b6,168)+Z(b5,169)+Z(b4,170)+Z(b3,171)+Z(b2,172)+Z(b1,173);
            UM2C(k,dptr);
            sorti_buf[j++]=k;
         }
         CHECK_RETURN(write_lut_block_int(lut,typ,dptr-data,data));

            /* Index-Block für IBAN-Regel generieren */
         if(add_idx){
            data_idx=dptr;
            for(i=0;i<j;i++)iptr[i]=i;   /* Index-Array initialisieren */
            qsort(iptr,j,sizeof(int),qcmp_sorti);
            UI2C(j,dptr);
            for(i=0;i<j;i++)UI2C(iptr[i],dptr);
            CHECK_RETURN(write_lut_block_int(lut,LUT2_IBAN_REGEL_SORT+(typ-LUT2_IBAN_REGEL),dptr-data_idx,data_idx));
         }
         break;

   }
   return OK;
}

/* Funktion generate_lut2_p() +§§§1 */
/* ###########################################################################
 * # Diese Funktion dient zur Generierung einer LUT-Datei.                   #
 * # Sie hat ein ähnliches Aufrufinterface wie die Funktion generate_lut2(), #
 * # die sie aufruft; allerdings ist der Parameter felder hier kein Array,   #
 * # sondern eine Integer-Variable, da die Übergabe eines Integer-Arrays     #
 * # von Perl Probleme machte. Sie ist daher etwas weniger flexibel als      #
 * # generate_lut2(), aber die Funktionalität reicht in der Praxis normaler- #
 * # weise gut aus.                                                          #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int generate_lut2_p(char *inputname,char *outputname,char *user_info,char *gueltigkeit,
      UINT4 felder,UINT4 filialen,int slots,int lut_version,int set)
{
   int i,j;
   UINT4 *felder1,felder2[MAX_SLOTS+1];

      /* Es werden defaultmäßig mindestens 60 Slots angelegt. Die Slots brauchen nicht viel
       * Speicher (12 Byte/Slot), aber das Slotdirectory läßt sich nachträglich nicht mehr
       * vergrößern. Falls die Datei mit zu wenigen Slots angelegt ist, können u.U. keine
       *  Blocks mehr eingefügt werden.
       *  In den folgenden Statements ist jeweils angegeben, wieviele Slots für den jeweiligen
       *  Satz mindestens benötigt werden.
       */

   switch(felder){
      case 0:  felder1=(UINT4 *)lut_set_0; if(!slots)slots=60; break;   /*  5 Slots/Satz */
      case 1:  felder1=(UINT4 *)lut_set_1; if(!slots)slots=60; break;   /*  7 Slots/Satz */
      case 2:  felder1=(UINT4 *)lut_set_2; if(!slots)slots=60; break;   /*  9 Slots/Satz */
      case 3:  felder1=(UINT4 *)lut_set_3; if(!slots)slots=60; break;   /* 11 Slots/Satz */
      case 4:  felder1=(UINT4 *)lut_set_4; if(!slots)slots=60; break;   /* 13 Slots/Satz */
      case 5:  felder1=(UINT4 *)lut_set_5; if(!slots)slots=60; break;   /* 14 Slots/Satz */
      case 6:  felder1=(UINT4 *)lut_set_6; if(!slots)slots=60; break;   /* 15 Slots/Satz */
      case 7:  felder1=(UINT4 *)lut_set_7; if(!slots)slots=60; break;   /* 16 Slots/Satz */
      case 8:  felder1=(UINT4 *)lut_set_8; if(!slots)slots=60; break;   /* 17 Slots/Satz */
      case 9:  felder1=(UINT4 *)lut_set_9; if(!slots)slots=60; break;   /* 19 Slots/Satz */
      default: felder1=(UINT4 *)NULL;      if(!slots)slots=60; break;   /* 19 Slots/Satz */
   }
   i=0;
   felder2[i++]=LUT2_BLZ;
   felder2[i++]=LUT2_PZ;
   if(filialen)felder2[i++]=LUT2_FILIALEN;
   if(filialen)felder2[i++]=LUT2_VOLLTEXT_TXT;
   for(j=0;i<MAX_SLOTS && felder1[j];)felder2[i++]=felder1[j++];
   felder2[i]=0;

   RETURN(generate_lut2(inputname,outputname,user_info,gueltigkeit,felder2,slots,lut_version,set));
}

/* Funktion generate_lut2() +§§§1 */
/* ###########################################################################
 * # Diese Funktion dient zur Generierung einer LUT-Datei. Eingabedatei ist  #
 * # eine Bundesbankdatei (Textform); dabei wird sowohl die einfache Version #
 * # ohne IBAN-Regeln als auch die erweiterte Form mit IBAN-Regeln erkannt   #
 * # und richtig ausgewertet (mittels der Zeilenlänge).                      #
 * # In die generierte LUT-Datei werden noch vier Testbanken eingefügt, die  #
 * # für einige Prüfziffermethoden (52, 53, B6) benötigt werden (sie sind in #
 * # den Beispielen enthalten, haben aber keine reale Entsprechung).         #
 * #                                                                         #
 * # Copyright (C) 2007, 2013 Michael Plugge <m.plugge@hs-mannheim.de>       #
 * ###########################################################################
 */

DLL_EXPORT int generate_lut2(char *inputname,char *outputname,const char *user_info,
      char *gueltigkeit,UINT4 *felder,UINT4 slots,UINT4 lut_version,UINT4 set)
{
   char *buffer,*out_buffer,*ptr,*zptr,*dptr;
   const char *testbanken,*testbanken_alt,*testbanken_neu;
   UINT4 bufsize,adler,g1,g2;
   int cnt,bank_cnt,i,j,k,file_format,line_end,retval,h,auch_filialen,prev_blz,b,
       diff,ok,add_idx,have_iban_rules,felder_fertig[LAST_LUT_BLOCK+1];
   struct stat s_buf;
   FILE *in,*lut;
   time_t t;
   struct tm timebuf,*timeptr;

   have_iban_rules=0;
   if(set<10)
      add_idx=1;
   else{
      set-=10;
      add_idx=0;
   }
   for(i=0;i<LAST_LUT_BLOCK;i++)felder_fertig[i]=0;
   lut=NULL;
   ok=OK;
   if(!gueltigkeit || !*gueltigkeit){
      gueltigkeit=(char*)"";
      g1=g2=0;
   }
   else{
      if(strlen(gueltigkeit)!=17)RETURN(LUT2_INVALID_GUELTIGKEIT);
      for(i=0,ptr=gueltigkeit;i<8;i++)if(!isdigit(*ptr++))RETURN(LUT2_INVALID_GUELTIGKEIT);
      if(*ptr!=' ' && *ptr++!='-')RETURN(LUT2_INVALID_GUELTIGKEIT);
      for(i=0;i<8;i++)if(!isdigit(*ptr++))RETURN(LUT2_INVALID_GUELTIGKEIT);
      g1=strtoul(gueltigkeit,NULL,10);
      g2=strtoul(gueltigkeit+9,NULL,10);
      if(g2<g1)RETURN(LUT2_GUELTIGKEIT_SWAPPED);
   }

      /* hier kommen einige Testbanken, die in der Beschreibung der
       * Prüfziffermethoden vorkommen, aber in der Bankleitzahlendatei nicht
       * mehr(?) enthalten sind. Da die Sortierung stabil ist, rutschen sie bei
       * der Sortierung ganz nach hinten. Falls es dann doch mal eine Bank mit
       * der BLZ gibt, würde die Testbank dadurch ignoriert (es wird immer die
       * erste mögliche BLZ gewählt). Sie werden einfach an den Buffer mit der
       * Bundesbankdatei angehängt und durch das Sortieren auf den richtigen
       * Platz geschoben.
       *
       * Es gibt zwei Versionen der Testbanken, mit und ohne IBAN-Regel.
       */
   testbanken_alt=
         "130511721Testbank Verfahren 52                                     57368Elsperhusen                        Testbank 52 Elsperhusen    13145TESTDEX987652130000U000000000\n"
         "160520721Testbank Verfahren 53                                     57368Elsperhusen                        Testbank 53 Elsperhusen    13145TESTDEX987653130000U000000000\n"
         "800537721Testbank Verfahren B6                                     57368Elsperhusen                        Testbank B6 Elsperhusen    13145TESTDEX9876B6130000U000000000\n"
         "800537821Testbank Verfahren B6                                     57368Elsperhusen                        Testbank B6 Elsperhusen    13145TESTDEX9876B6130000U000000000\n";
   testbanken_neu=
         "130511721Testbank Verfahren 52                                     57368Elsperhusen                        Testbank 52 Elsperhusen    13145TESTDEX987652130000U000000000000000\n"
         "160520721Testbank Verfahren 53                                     57368Elsperhusen                        Testbank 53 Elsperhusen    13145TESTDEX987653130000U000000000000000\n"
         "800537721Testbank Verfahren B6                                     57368Elsperhusen                        Testbank B6 Elsperhusen    13145TESTDEX9876B6130000U000000000000000\n"
         "800537821Testbank Verfahren B6                                     57368Elsperhusen                        Testbank B6 Elsperhusen    13145TESTDEX9876B6130000U000000000000000\n";
   if(!init_status&1)init_atoi_table();
   if(!felder)felder=(UINT4 *)DEFAULT_LUT_FIELDS;
   if(!lut_version)lut_version=DEFAULT_LUT_VERSION;
#if GENERATE_OLD_LUTFILE==0
   if(lut_version<3){
      lut_version=3;  /* keine alten LUT-Dateien mehr generieren */
      ok=LUT_V2_FILE_GENERATED;
   }
#endif
   if(!slots)slots=DEFAULT_SLOTS;
   if(slots<SLOT_CNT_MIN){
      slots=SLOT_CNT_MIN; /* Minimalzahl Slots */
      ok=OK_SLOT_CNT_MIN_USED;
   }
   if(!outputname)outputname=(char *)default_lutname[0];
   if(stat(inputname,&s_buf)==-1)RETURN(FILE_READ_ERROR);
   bufsize=s_buf.st_size+10+strlen(testbanken_neu);
   if(!(buffer=(char *)malloc(bufsize)) || !(out_buffer=(char *)malloc(bufsize)))RETURN(ERROR_MALLOC);
   if(!(in=fopen(inputname,"rb"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(rb)");
      if(buffer)FREE(buffer);
      if(out_buffer)FREE(out_buffer);
      RETURN(FILE_READ_ERROR);
   }
   cnt=fread(buffer,1,s_buf.st_size,in);
   for(ptr=buffer;*ptr!='\r' && *ptr!='\n';ptr++);
   line_end=ptr-buffer;
   if(line_end==168){
      file_format=1; /* Dateiformat ohne IBAN-Regeln */
      testbanken=testbanken_alt;
   }
   else if(line_end==174){
      file_format=2; /* Dateiformat mit IBAN-Regeln */
      testbanken=testbanken_neu;
   }
   else{
      file_format=0; /* unbekannnt oder uralt */
      testbanken=testbanken_neu;
   }

   dptr=buffer+cnt;
   for(ptr=(char*)testbanken;(*dptr++=*ptr++);cnt++);
   bank_cnt=cnt/line_end; /* etwas zuviel allokieren, aber so ist es sicherer (CR/LF wird bei der Datensatzlänge nicht mitgezählt) */

      /* Speicher für die Arrays allokieren */
   if(!(qs_zeilen=(char **)calloc(bank_cnt,sizeof(char *)))
         || !(qs_blz=(int *)calloc(bank_cnt,sizeof(int)))
         || !(qs_hauptstelle=(char *)calloc(bank_cnt,1))
         || !(qs_plz=(int *)calloc(bank_cnt,sizeof(int)))
         || !(qs_sortidx=(int *)calloc(bank_cnt,sizeof(int)))
         || !(qs_iban_regel=(int *)calloc(bank_cnt,sizeof(int)))){
      FREE(buffer);
      FREE(out_buffer);
      FREE(qs_zeilen);
      FREE(qs_blz);
      FREE(qs_hauptstelle);
      FREE(qs_plz);
      FREE(qs_sortidx);
      FREE(qs_iban_regel);
      RETURN(ERROR_MALLOC);
   }

      /* BLZ-Datei auswerten, testen und sortieren */
   for(i=h=0,ptr=buffer;i<bank_cnt && *ptr;i++){
      qs_zeilen[i]=ptr;
      qs_sortidx[i]=i;
      qs_blz[i]=b8[(int)*ptr]+b7[(int)*(ptr+1)]+b6[(int)*(ptr+2)]+b5[(int)*(ptr+3)]+b4[(int)*(ptr+4)]+b3[(int)*(ptr+5)]+b2[(int)*(ptr+6)]+b1[(int)*(ptr+7)];
      qs_hauptstelle[i]=*(ptr+8);
      if(qs_hauptstelle[i]=='1')h++;
      qs_plz[i]=b5[(int)*(ptr+67)]+b4[(int)*(ptr+68)]+b3[(int)*(ptr+69)]+b2[(int)*(ptr+70)]+b1[(int)*(ptr+71)];
      if(file_format==2)
         qs_iban_regel[i]=b6[(int)*(ptr+168)]+b5[(int)*(ptr+169)]+b4[(int)*(ptr+170)]+b3[(int)*(ptr+171)]+b2[(int)*(ptr+172)]+b1[(int)*(ptr+173)];
      else
            /* keine IBAN-Regeln in der BLZ-Datei enthalten; den Block aus der Liste löschen */
         for(j=0;felder[j];j++)if(felder[j]==LUT2_IBAN_REGEL)for(k=j+1;(felder[j]=felder[k]);j++,k++)while(felder[k]==LUT2_IBAN_REGEL)k++;

      for(j=0;j<line_end;j++)if(!*ptr || *ptr=='\r' || *ptr=='\n'){
         retval=INVALID_BLZ_FILE;
         goto fini;
      }
      else
         ptr++;
      while(*ptr=='\r')*ptr++=0;
      if(*ptr!='\n'){   /* es werden nur noch Dateien im neuen Format akzeptiert (nach 7/2006) */
         retval=INVALID_BLZ_FILE;
         goto fini;
      }
      else
         *ptr++=0;
   }
   bank_cnt=i;
   qsort(qs_sortidx,bank_cnt,sizeof(int),sort_cmp);

   if(!user_info)
      user_info=(char*)"";
   else   /* newlines sind in der user_info Zeile nicht zulässig; in Blanks umwandeln */
      for(ptr=(char*)user_info;*ptr;ptr++)if(*ptr=='\r' || *ptr=='\n')*ptr=' ';

      /* nachsehen, ob das Feld LUT2_FILIALEN in der Liste ist; falls nicht, nur Hauptstellen aufnehmen */
   for(i=auch_filialen=0;felder[i] && i<MAX_SLOTS;i++)if(felder[i]==LUT2_FILIALEN)auch_filialen=1;

   t=time(NULL);
   timeptr=localtime_r(&t,&timebuf);
   if(lut_version<3){

         /* zunächst mal die alte Version behandeln; der Code wurde
          * größtenteils aus Version 2.4 übernommen. Bei der Generierung der
          * LUT-Datei ergeben sich allerdings manchmal Differenzen, und zwar
          * wenn für eine BLZ mehrere Prüfmethoden angegeben sind; diese
          * Version benutzt dann die Methode der Hauptstelle, während die alte
          * Version den zuletzt auftretenden Wert benutzte; das ist i.A. der
          * einer Nebenstelle. Allerdings ist der Wert normalerweise falsch, da
          * für die Hauptstelle scheinbar zuerst der neue Code eingetragen wird
          * und dann erst für die Nebenstellen (z.B. ist in blz_20070604.txt
          * für die BLZ 15051732 für die Hauptstelle die Methode C0
          * eingetragen, für die Nebenstellen die Methode 52; die Methode C0
          * enthält die Methode 52 als Variante 1. Ein analoges Vorgehen findet
          * sich in blz_20071203.txt bei der BLZ 76026000: die Hauptstelle hat
          * die Prüfmethode C7, die Nebenstellen die Methode 06.
          *
          * In Version 2.5 wurde die Generierung umgestellt und benutzt auch
          * nur noch die Methode der Hauptstelle.
          */ 
      if(!(lut=fopen(outputname,"wb"))){
         PRINT_VERBOSE_DEBUG_FILE("fopen(wb)");
         return(FILE_WRITE_ERROR);
      }
      switch(lut_version){   /* Datei-Signatur */
         case 1:
            fprintf(lut,"BLZ Lookup Table/Format 1.0\n");
            break;

         case 2:
            fprintf(lut,"BLZ Lookup Table/Format 1.1\n");
            fprintf(lut,"LUT-Datei generiert am %d.%d.%d, %d:%02d aus %s",
                  timeptr->tm_mday,timeptr->tm_mon+1,timeptr->tm_year+1900,timeptr->tm_hour,
                  timeptr->tm_min,inputname);
            if(user_info && *user_info)
               fprintf(lut,"\\\n%s\n",user_info);
            else
               fputc('\n',lut);
            break;

         default:
            break;
      }
      for(i=prev_blz=0,dptr=out_buffer;i<bank_cnt;i++){
         b=qs_blz[qs_sortidx[i]];
            /* Prüfziffermethoden nur für die Hauptstellen und Testbanken */
         if(qs_hauptstelle[qs_sortidx[i]]=='1' || qs_hauptstelle[qs_sortidx[i]]=='3'){
            zptr=qs_zeilen[qs_sortidx[i]];

            /* Format (1.0 und 1.1) der Lookup-Datei für blz:
             *    - Signatur und Version
             *    - (ab Version 1.1) Infozeile mit Erstellungsdatum und Source-Dateiname
             *                       evl. User-Infozeile
             *    - 4 Byte Anzahl Bankleitzahlen
             *    - 4 Byte Prüfsumme
             *    - Bankleitzahlen (komprimiert):
             *       - bei Differenz zur letzten BLZ
             *            1...250         : *kein* Kennbyte, 1 Byte Differenz
             *            251...65535     : Kennbyte 254, 2 Byte Differenz
             *            >65536/<-65535  : Kennbyte 253, 4 Byte Wert der BLZ, nicht Differenz
             *            -1...-255       : Kennbyte 252, 1 Byte Differenz (obsolet wegen Sortierung)
             *            -256...-65535   : Kennbyte 251, 2 Byte Differenz (obsolet wegen Sortierung)
             *                              Kennbyte 255 ist reserviert
             *    - ein Byte mit der zugehörigen Methode.
             */

            diff=b-prev_blz;
            prev_blz=b;
            if(diff==0)
               continue;
            else if(diff>0 && diff<=250){
               *dptr++=diff&255;
            }
            else if(diff>250 && diff<65536){   /* 2 Byte, positiv */
               *dptr++=254;
               *dptr++=diff&255;
               diff>>=8;
               *dptr++=diff&255;
            }
            else if(diff>65535){   /* Wert direkt eintragen */
               *dptr++=253;
               *dptr++=b&255;
               b>>=8;
               *dptr++=b&255;
               b>>=8;
               *dptr++=b&255;
               b>>=8;
               *dptr++=b&255;
            }
            /* negative Werte können aufgrund der Sortierung nicht mehr auftreten,
             * die Kennzeichen 251 und 252 entfallen daher.
             */

            *dptr++=bx2[UI *(zptr+150)]+bx1[UI *(zptr+151)];  /* Methode */
         }
      }
         /* adler32 müßte eigentlich mit 1 als erstem Parameter aufgerufen
          * werden; das wurde bei der ersten Version verschlafen, und bleibt nun
          * aus Kompatiblitätsgründen natürlich auch weiterhin so :-(. In den
          * neuen Dateiversionen wird der richtige Aufruf verwendet.
          */
      adler=adler32a(0,(char *)out_buffer,dptr-out_buffer)^h;  /* Prüfsumme */
      WRITE_LONG(h,lut);
      WRITE_LONG(adler,lut);
      if(fwrite((char *)out_buffer,1,dptr-out_buffer,lut)<(size_t)(dptr-out_buffer)){
         PRINT_VERBOSE_DEBUG_FILE("fwrite");
         retval=FILE_WRITE_ERROR;       /* BLZ-Liste */
         goto fini;
      }
      if(gueltigkeit || felder || slots || set)
            /* verdächtig, Warnung ausgeben (es sollte wohl eine LUT2 Datei erzeugt werden) */
         retval=LUT1_FILE_GENERATED;
      else
         retval=OK;
      goto fini;
   }

   sprintf(out_buffer,"Gueltigkeit der Daten: %08u-%08u (%s Datensatz)\nEnthaltene Felder:",
         g1,g2,set<2?"Erster":"Zweiter");
   for(i=0,ptr=out_buffer;felder[i];i++){
         /* testen, ob ein ungültiges oder schon berücksichtigtes Feld angegeben wurde */
      if(felder[i]<1 || felder[i]>LAST_LUT_BLOCK
            || felder[i]==LUT2_OWN_IBAN || felder[i]==LUT2_2_OWN_IBAN   /* wird nur in eigener Funktion eingefügt */
            || felder_fertig[felder[i]])continue;
      felder_fertig[felder[i]]=1;
      while(*ptr)ptr++;
      if(i>0)*ptr++=',';
      *ptr++=' ';
      sprintf(ptr,"%s%s",lut_block_name1[felder[i]],add_idx && lut_block_idx[felder[i]]?"+":"");
   }
   for(i=0;felder[i] && i<MAX_SLOTS;i++)if(felder[i]==LUT2_IBAN_REGEL || felder[i]==LUT2_2_IBAN_REGEL)have_iban_rules=1;
   while(*ptr)ptr++;
   *ptr++='\n';
   *ptr++='\n';

      /* eine inkrementelle Initialisierung sollte nur von derselben Datei
       * erfolgen können, mit der sie begonnen wurde; daher wird eine zufällige
       * Datei-ID generiert (relativ anspruchslos, mittels rand()) und in den
       * Prolog geschrieben. Bei einer inkrementellen Initialisierung wird
       * dieser String ebenfalls getestet; falls er sich von der ursprünglichen
       * Version unterscheidet, wird eine inkrementelle Initialisierung mit
       * einer Fehlermeldung beendet, um Inkonsitenzen zu vermeiden.
       */
   srand(time(NULL)+getpid());   /* Zufallszahlengenerator initialisieren */
   sprintf(ptr,"BLZ Lookup Table/Format 2.0\nLUT-Datei generiert am %d.%d.%d, %d:%02d aus %s%s%s\n"
         "Anzahl Banken: %d, davon Hauptstellen: %d (inkl. %d Testbanken)\n"
         "dieser Datensatz enthaelt %s, %s und %sIBAN-Regeln\n"
         "Kompression: %s\nDatei-ID (zufaellig, fuer inkrementelle Initialisierung):\n"
         "%04x%04x%04x%04x%04x%04x%04x%04x\n",
         timeptr->tm_mday,timeptr->tm_mon+1,timeptr->tm_year+1900,timeptr->tm_hour,
         timeptr->tm_min,inputname,*user_info?"\\\n":"",user_info,
         bank_cnt,h,(int)strlen(testbanken)/168,auch_filialen?"auch die Filialen":"nur die Hauptstellen",
         add_idx?"sowie Indexblocks":"keine Indexblocks",
         have_iban_rules?"":"keine ",
         compr_str[compression_lib],
         rand()&32767,rand()&32767,rand()&32767,rand()&32767,rand()&32767,rand()&32767,rand()&32767,rand()&32767);

      /* die ersten beiden Zeilen sind nur für den Gültigkeitsblock, nicht für den Vorspann */
   for(ptr=out_buffer;*ptr++!='\n';);
   while(*ptr++!='\n');
   ptr++;   /* Leerzeile überspringen */

      /* falls ein set angegeben ist, die datei aber nicht existiert, eine neue Datei anlegen (set=0) */
   if(set>0 && stat(outputname,&s_buf)==-1)set=0;
   if(set>0){  /* Blocks an Datei anhängen */
      if(!(lut=fopen(outputname,"rb+"))){
         PRINT_VERBOSE_DEBUG_FILE("fopen(rb+)");
         retval=FILE_WRITE_ERROR;
         goto fini;
      }
   }
   else  /* neue LUT-Datei erzeugen */
      CHECK_RETVAL(create_lutfile_int(outputname,ptr,slots,&lut));

      /* Block mit Gültigkeitsdatum und Beschreibung des Satzes schreiben */
   if(set<2)
      CHECK_RETVAL(write_lut_block_int(lut,LUT2_INFO,strlen(out_buffer),out_buffer));
   else
      CHECK_RETVAL(write_lut_block_int(lut,LUT2_2_INFO,strlen(out_buffer),out_buffer));

      /* Felder der deutschen BLZ-Datei schreiben */
   for(i=0;felder[i] && i<MAX_SLOTS;i++)
      if(felder[i]>0 && felder[i]<=LAST_LUT_BLOCK){
         retval=write_lutfile_entry_de(UI felder[i],auch_filialen,bank_cnt,out_buffer,lut,set,add_idx);
      }

fini:
   if(lut)fclose(lut);  
   fclose(in);
   FREE(buffer);
   FREE(out_buffer);
   FREE(qs_zeilen);
   FREE(qs_blz);
   FREE(qs_hauptstelle);
   FREE(qs_plz);
   FREE(qs_sortidx);
   FREE(qs_iban_regel);
   qs_hauptstelle=NULL;
   qs_zeilen=NULL;
   qs_blz=qs_plz=qs_sortidx=NULL;
   if(retval==OK)retval=ok;
   RETURN(retval);
}

/* Funktion lut_dir_dump() und lut_dir_dump_str() +§§§1 */
/* ###########################################################################
 * # Diese Funktionen lesen eine LUT-Datei und schreiben Infos zu den ent-   #
 * # haltenen Blocks in die Ausgabedatei (bzw. den Ausgabestring). Falls für #
 * # outputname NULL oder ein Leerstring angegeben wird, werden die Daten    #
 * # nach stdout geschrieben. Außerdem wird noch die Gesamtgröße der Daten   #
 * # (sowohl komprimiert als auch unkomprimiert) ausgegeben.                 #
 * #                                                                         #
 * # Die Funktion lut_dir_dump_str() allokiert für die Ausgabe Speicher;     #
 * # dieser muß von dre aufrufenden Funktion wieder freigegeben werden.      #
 * #                                                                         #
 * # Copyright (C) 2007-2010 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

DLL_EXPORT int lut_dir_dump(char *lutname,char *outputname)
{
   char *ptr;
   int retval;
   FILE *out;

   if((retval=lut_dir_dump_str(lutname,&ptr))<OK){
      if(ptr)free(ptr);
      RETURN(retval);
   }
   if(!outputname || !*outputname){
      fprintf(stderr,"%s\n\n",ptr);
      if(ptr)free(ptr);
      return OK;
   }
   else if(!(out=fopen(outputname,"w"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(w)");
      free(ptr);
      RETURN(FILE_WRITE_ERROR);
   }
   fprintf(out,"%s\n\n",ptr);
   free(ptr);
   fclose(out);
   return OK;
}

DLL_EXPORT int lut_dir_dump_id(char *lutname,int *rv)
{
   char *ptr;
   int retval,id;

   if((retval=lut_dir_dump_str(lutname,&ptr))<OK){
      if(ptr)free(ptr);
      if(rv)*rv=retval;
      return -1;
   }
   if((retval=kc_ptr2id(ptr,&id,1))<0)free(ptr);
   if(rv)*rv=retval;
   return id;
}

DLL_EXPORT int lut_dir_dump_str(char *lutname,char **dptr)
{
   char *ptr;
   int i,retval,len1,len2,compression_mode,slotdir[MAX_SLOTS];
   UINT4 slot_cnt,typ,len,compressed_len,adler;
   FILE *lut;

   *dptr=NULL;
   if(!(lut=fopen(lutname,"rb"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(rb)");
      RETURN(FILE_READ_ERROR);
   }
   retval=lut_dir(lut,0,&slot_cnt,NULL,NULL,NULL,NULL,slotdir,&compression_mode);
   if(retval!=OK){
      fclose(lut);
      RETURN(retval);
   }
   if(!(ptr=(char *)malloc(slot_cnt*90+500))){
      fclose(lut);
      RETURN(ERROR_MALLOC);
   }
   *dptr=ptr;
   sprintf(ptr," Slot retval   Typ   Inhalt                  Laenge   kompr.   Verh.    Adler32  Test\n");
   while(*ptr)ptr++;
   for(len1=len2=0,i=slot_cnt=1;i<=(int)slot_cnt;i++){
      retval=lut_dir(lut,i,&slot_cnt,&typ,&len,&compressed_len,&adler,NULL,NULL);
      if(retval==LUT2_FILE_CORRUPTED || retval==KTO_CHECK_UNSUPPORTED_COMPRESSION){
         fclose(lut);
         RETURN(retval);
      }
      if(typ)
         sprintf(ptr,"%2d/%2u %3d %8d   %-20s %8u %8u%7.1f%%  0x%08x   %s\n",
               i,slot_cnt,retval,typ,typ<400?lut_block_name2[typ]:"(Userblock)",
               len,compressed_len,len?(double)compressed_len/len*100:0,adler,retval==OK?"OK":"FEHLER");
      else
         sprintf(ptr,"%2d/%2u %3d %8d   %-20s %8u %8u%7s   0x%08x   %s\n",i,slot_cnt,1,0,"   (ungenutzt)",0,0,"-",0,"OK");
      while(*ptr)ptr++;
      len1+=len;
      len2+=compressed_len;
   }
   sprintf(ptr,"\nGesamtgroesse unkomprimiert: %d, Gesamtgroesse komprimiert: %d\nKompressionsrate: %1.2f%% (Kompression: %s)\nSlotdir (kurz): ",
         len1,len2,100.*(double)len2/len1,compr_str[compression_mode]);
   while(*ptr)ptr++;
   for(i=0;i<(int)slot_cnt;i++)if(slotdir[i]){
      sprintf(ptr,"%d ",slotdir[i]);
      while(*ptr)ptr++;
   }
   *ptr++='\n';
   *ptr=0;
   fclose(lut);
   return OK;
}

/* Funktion lut_valid() +§§§1 */
/* ###########################################################################
 * # Die Funktion lut_valid() testet, ob die geladene LUT-Datei aktuell      #
 * # gültig ist. Im Gegensatz zu lut_info wird kein Speicher allokiert.      #
 * #                                                                         #
 * # Rückgabewerte:                                                          #
 * #    LUT2_VALID:             Der Datenblock ist aktuell gültig            #
 * #    LUT2_NO_LONGER_VALID:   Der Datenblock ist nicht mehr gültig         #
 * #    LUT2_NOT_YET_VALID:     Der Datenblock ist noch nicht gültig         #
 * #    LUT2_NO_VALID_DATE:     Der Datenblock enthält kein Gültigkeitsdatum #
 * #    LUT2_NOT_INITIALIZED:   die library wurde noch nicht initialisiert   #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */
DLL_EXPORT int lut_valid(void)
{
   time_t t;
   struct tm timebuf,*timeptr;
   UINT4 current;

   if((init_status&7)<7)RETURN(LUT2_NOT_INITIALIZED);
#if DEBUG>0
   if(current_date)
      current=current_date;
   else{
#endif
      t=time(NULL);
      timeptr=localtime_r(&t,&timebuf);
      current=(timeptr->tm_year+1900)*10000+(timeptr->tm_mon+1)*100+timeptr->tm_mday;  /* aktuelles Datum als JJJJMMTT */
#if DEBUG>0
   }
#endif
   if(!current_v1 || !current_v2) /* (mindestens) ein Datum fehlt */
      RETURN(LUT2_NO_VALID_DATE);
   else if(current>=current_v1 && current<=current_v2)
      RETURN(LUT2_VALID);
   else if(current<current_v1)
      RETURN(LUT2_NOT_YET_VALID);
   else  /* if(current>current_v2)  */
      RETURN(LUT2_NO_LONGER_VALID);
}


/* Funktion lut_info_b() +§§§1 */
/* ###########################################################################
 * # Die Funktion lut_info_b() stellt den VB-Port zu der Funktion lut_info() #
 * # dar. Sie ruft die Funktion lut_info() auf und kopiert das Funktions-    #
 * # ergebnis in die (**von VB zur Verfügung gestellten**) Variablen info1   #
 * # und info2; danach wird der Speicher der von lut_info() allokiert wurde, #
 * # wieder freigegeben.                                                     #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_info_b(char *lut_name,char **info1,char **info2,int *valid1,int *valid2)
{
   char *i1,*i2;
   int retval;

   retval=lut_info(lut_name,&i1,&i2,valid1,valid2);
   if(i1){
      strncpy(*info1,i1,1024);
      FREE(i1);
   }
   else
      **info1=0;
   if(i2){
      strncpy(*info2,i2,1024);
      FREE(i2);
   }
   else
      **info2=0;
   return retval;
}


/* Funktion lut_info_id() +§§§1 */
/* ###########################################################################
 * # Die Funktion lut_info_id() ist ähnlich wie lut_info_b(). Für die        #
 * # Parameter info1 und info2 wird jedoch ein Handle zurückgegeben, das     #
 * # mittels der Funktion kc_id2ptr() in einen String umgewandelt, sowie mit #
 * # der Funktion kc_id_free() wieder freigegeben werden kann.               #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_info_id(char *lut_name,int *info1,int *info2,int *valid1,int *valid2)
{
   char *i1,*i2;
   int retval,rv;

   retval=lut_info(lut_name,&i1,&i2,valid1,valid2);
   if(i1){
      if((rv=kc_ptr2id(i1,info1,1))<0){
         FREE(i1);
         FREE(i2);
         return rv;
      }
   }
   else
      *info1=-1;
   if(i2){
      if((rv=kc_ptr2id(i2,info2,1))<0){
         FREE(i1);
         FREE(i2);
         return rv;
      }
   }
   else
      *info2=-1;
   return retval;
}


/* Funktion lut_info() +§§§1 */
/* ###########################################################################
 * # Die Funktion lut_info() extrahiert die beiden Infoblocks aus einer      #
 * # LUT-Datei und vergleicht das Gültigkeitsdatum mit dem aktuellen Datum.  #
 * # Falls eine LUT-Datei keinen Infoblock oder kein Gültigkeitsdatum        #
 * # enthält, wird (in den Variablen valid1 bzw. valid2) ein entsprechender  #
 * # Fehlercode zurückgegeben. Die Funktion allokiert Speicher für die       #
 * # Infoblocks; dieser muß von der aufrufenden Routine wieder freigegeben   #
 * # werden.                                                                 #
 * #                                                                         #
 * # Falls als Dateiname NULL oder ein Leerstring übergeben wird, wird die   #
 * # Gültigkeit des aktuell geladenen Datensatzes bestimmt, und (optional)   #
 * # mit dem zugehörigen Infoblock zurückgegeben. In diesem Fall wird info2  #
 * # auf NULL und valid2 auf LUT2_BLOCK_NOT_IN_FILE gesetzt.                 #
 * #                                                                         #
 * # Falls ein Parameter nicht benötigt wird, kann man für den Parameter     #
 * # einfach NULL übergeben.                                                 #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    lut_name: Name der LUT-Datei oder NULL/Leerstring                    #
 * #    info1:    Pointer, der auf den primären Infoblock gesetzt wird       #
 * #    info2:    Pointer, der auf den sekundären Infoblock gesetzt wird     #
 * #    valid1:   Statusvariable für den primären Datensatz                  #
 * #    valid2:   Statusvariable für den sekundären Datensatz                #
 * #                                                                         #
 * # Rückgabewerte:                                                          #
 * #    OK:                     ok, weiteres in valid1 und valid2            #
 * #    LUT2_NOT_INITIALIZED:   die library wurde noch nicht initialisiert   #
 * #                                                                         #
 * # Werte für valid1 und valid2:                                            #
 * #    LUT2_VALID:             Der Datenblock ist aktuell gültig            #
 * #    LUT2_NO_LONGER_VALID:   Der Datenblock ist nicht mehr gültig         #
 * #    LUT2_NOT_YET_VALID:     Der Datenblock ist noch nicht gültig         #
 * #    LUT2_NO_VALID_DATE:     Der Datenblock enthält kein Gültigkeitsdatum #
 * #    LUT2_BLOCK_NOT_IN_FILE: Die LUT-Datei enthält den Infoblock nicht    #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_info(char *lut_name,char **info1,char **info2,int *valid1,int *valid2)
{
   char *ptr,*ptr1,buffer[128];
   int i,j,ret;
   UINT4 v1,v2,v2a=0,current,cnt;
   time_t t;
   struct tm timebuf,*timeptr;
   FILE *in;

   t=time(NULL);
   timeptr=localtime_r(&t,&timebuf);
   current=(timeptr->tm_year+1900)*10000+(timeptr->tm_mon+1)*100+timeptr->tm_mday;  /* aktuelles Datum als JJJJMMTT */
#if DEBUG>0
   if(current_date)current=current_date;
#endif

      /* Gültigkeit des aktuell geladenen Datensatzes testen */
   if(!lut_name || !*lut_name){
      if((init_status&7)<7){
         if(info1)*info1=NULL;
         if(info2)*info2=NULL;
         if(valid1)*valid1=LUT2_NOT_INITIALIZED;
         if(valid2)*valid2=LUT2_NOT_INITIALIZED;
         RETURN(LUT2_NOT_INITIALIZED);
      }
      if(info1){
         if(!current_info)
            *info1=NULL;
         else{
            *info1=ptr=(char *)malloc(current_info_len+8192);
            sprintf(ptr,"%s\nin den Speicher geladene Blocks:\n   ",current_info);
            while(*ptr)ptr++;
            ptr1=*info1+current_info_len+8000;
            for(i=j=0;i<SET_OFFSET && ptr<ptr1;i++)if(lut2_block_status[i+set_offset]==OK){
               while(*ptr)ptr++;
               if(j>0)*ptr++=',';
               *ptr++=' ';
               sprintf(ptr,"%s",lut_block_name1[i]);
               j++;
            }
            while(*ptr)ptr++;
            *ptr++='\n';
            *ptr++=0;
            *info1=(char *)realloc(*info1,ptr-*info1+10);
         }
      }
      if(valid1){
         if(!current_v1 || !current_v2) /* (mindestens) ein Datum fehlt */
            *valid1=LUT2_NO_VALID_DATE;
         else if(current>=current_v1 && current<=current_v2)
            *valid1=LUT2_VALID;
         else if(current<current_v1)
            *valid1=LUT2_NOT_YET_VALID;
         else if(current>current_v2)
            *valid1=LUT2_NO_LONGER_VALID;
      }
      if(info2)*info2=NULL;
      if(valid2)*valid2=LUT2_BLOCK_NOT_IN_FILE;
      return OK;
   }

      /* Datensätze aus einer Datei */
   if(info1)*info1=NULL;
   if(info2)*info2=NULL;
   if(valid1)*valid1=0;
   if(valid2)*valid2=0;
   if(!(in=fopen(lut_name,"rb"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen");
      RETURN(FILE_READ_ERROR);
   }

      /* zunächst die LUT-Version testen */
   ptr=fgets(buffer,128,in);
   while(*ptr && *ptr!='\n')ptr++;
   *--ptr=0;
   if(!strcmp(buffer,"BLZ Lookup Table/Format 1.")){
      fclose(in);
      RETURN(LUT1_FILE_USED); /* alte LUT-Datei */
   }
   if(strcmp(buffer,"BLZ Lookup Table/Format 2.")){
      fclose(in);
      RETURN(INVALID_LUT_FILE); /* keine LUT-Datei */
   }
   rewind(in);

      /* Infoblocks lesen: 1. Infoblock */
   if((ret=read_lut_block_int(in,0,LUT2_INFO,&cnt,&ptr))==OK){
      *(ptr+cnt)=0;
      if(valid1){
         for(ptr1=ptr,v1=v2=0;*ptr1 && *ptr1!='\n' && !isdigit(*ptr1);ptr1++);
         if(*ptr1 && *ptr1!='\n'){
            v1=strtoul(ptr1,NULL,10);              /* Anfangsdatum der Gültigkeit */
            if(*ptr1 && *ptr1!='\n'){
               while(*ptr1 && *ptr1!='\n' && *ptr1++!='-');  /* Endedatum suchen */
               if(*ptr1)v2=strtoul(ptr1,NULL,10);  /* Endedatum der Gültigkeit */
            }
         }
         v2a=v2;
         if(!v1 || !v2){ /* (mindestens) ein Datum fehlt */
            *valid1=LUT2_NO_VALID_DATE;
            v2a=0;
         }
         else if(current>=v1 && current<=v2)
            *valid1=LUT2_VALID;
         else if(current<v1)
            *valid1=LUT2_NOT_YET_VALID;
         else if(current>v2)
            *valid1=LUT2_NO_LONGER_VALID;
      }
      if(info1)
         *info1=ptr;
      else
         FREE(ptr);
   }
   else{
      ret=get_lut_info2(lut_name,&i,&ptr,NULL,NULL);
      if(info1)
         *info1=ptr;
      else
         FREE(ptr);
      if(valid1){
         if(i<3)
            *valid1=LUT1_SET_LOADED;
         else
            *valid1=ret;
      }
      if(info2)*info2=NULL;
      if(valid2)*valid2=0;
      fclose(in);
      RETURN(ret);
   }

      /* Infoblocks lesen: 2. Infoblock */
   if((ret=read_lut_block_int(in,0,LUT2_2_INFO,&cnt,&ptr))==OK){
      *(ptr+cnt)=0;
      if(valid2){
         for(ptr1=ptr,v1=v2=0;*ptr1 && *ptr1!='\n' && !isdigit(*ptr1);ptr1++);
         if(*ptr1 && *ptr1!='\n'){
            v1=strtoul(ptr1,NULL,10);              /* Anfangsdatum der Gültigkeit */
            if(*ptr1 && *ptr1!='\n'){
               while(*ptr1 && *ptr1!='\n' && *ptr1++!='-');  /* Endedatum suchen */
               if(*ptr1)v2=strtoul(ptr1,NULL,10);  /* Endedatum der Gültigkeit */
            }
         }
         if(!v1 || !v2){ /* (mindestens) ein Datum fehlt */
            *valid2=LUT2_NO_VALID_DATE;
            v2=0;
         }
         else if(current>=v1 && current<=v2)
            *valid2=LUT2_VALID;
         else if(current<v1)
            *valid2=LUT2_NOT_YET_VALID;
         else if(current>v2){
               /* nur wenn in beiden Datensätzen das Gültigkeitsdatum vorhanden
                * ist, einen als besser klassifizieren
               */
            if(v2 && v2a && *valid1==LUT2_NO_LONGER_VALID){
                  /* beide Datensätze sind ungültig; den jüngeren der beiden
                   * als LUT2_NO_LONGER_VALID_BETTER markieren
                  */
               if(v2>v2a)
                  *valid2=LUT2_NO_LONGER_VALID_BETTER;
               else{
                  *valid1=LUT2_NO_LONGER_VALID_BETTER;
                  *valid2=LUT2_NO_LONGER_VALID;
               }
            }
            else
               *valid2=LUT2_NO_LONGER_VALID;
         }
      }
      if(info2)
         *info2=ptr;
      else
         FREE(ptr);
   }
   else{
      if(info2)*info2=NULL;
      if(valid2)*valid2=ret;
   }
   fclose(in);
   return OK;
}

/* Funktion get_lut_info2() +§§§1 */
/* ###########################################################################
 * # get_lut_info2(): Prolog, Infozeilen und Version einer LUT-Datei holen   #
 * #                                                                         #
 * # Die Funktion liest den Prolog einer LUT-Datei und wertet ihn aus; es    #
 * # werden verschiedene Variablen zurückgegeben, in denen die Prolog-Daten  #
 * # enthalten sind. Die Funktion allokiert Speicher für den Prolog; dieser  #
 * # muß vom aufrufenden Programm wieder freigegeben werden.                 #
 * #                                                                         #
 * # Die Werte der Info-Zeile und User-Info Zeile werden nur zurückgegeben,  #
 * # falls auch eine Variable für prolog spezifiziert ist. Es wird Speicher  #
 * # allokiert, der der Variablen prolog zugewiesen wird; für info und       #
 * # user_info wird kein eigener Speicherbereich benutzt.                    #
 * #                                                                         #
 * # Diese Funktion stammt noch aus dem alten Interface und liefert nur die  #
 * # Werte aus dem Prolog der LUT-Datei. Eine ähnliche Funktion ist für das  #
 * # neue LUT-Format ist lut_info(); diese extrahiert die Infoblocks der     #
 * # Datei und liefert auch eine Aussage über die Gültigkeit der Daten.      #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    lut_name:  Name der LUT-Datei                                        #
 * #    info:      Die Variable wird auf die Infozeile gesetzt               #
 * #    version_p: Variablenpointer für Rückgabe der LUT-Version             #
 * #    prolog_p:  Variablenpointer für Rückgabe des Prologs (per malloc!!)  #
 * #    info_p:    Variablenpointer für Rückgabe des Info-Strings            #
 * #    user_info_p: Variablenpointer für Rückgabe des User-Info-Strings     #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int get_lut_info2(char *lut_name,int *version_p,char **prolog_p,char **info_p,char **user_info_p)
{
   char *buffer,*ptr,*sptr,*info=(char*)"",*user_info=(char*)"",name_buffer[LUT_PATH_LEN];
   int i,j,k,buflen,version,zeile;
   unsigned long offset1,offset2;
   struct stat s_buf;
   FILE *lut;

   if(prolog_p)*prolog_p=NULL;
   if(info_p)*info_p=NULL;
   if(user_info_p)*user_info_p=NULL;

      /* falls keine LUT-Datei angegeben wurde, die Suchpfade und Defaultnamen durchprobieren */
   if(!lut_name || !*lut_name){
      for(i=0,k=-1,lut_name=name_buffer;i<lut_name_cnt && k==-1;i++){
         for(j=0;j<lut_searchpath_cnt;j++){
#if _WIN32>0
            snprintf(lut_name,LUT_PATH_LEN,"%s\\%s",lut_searchpath[j],default_lutname[i]);
#else
            snprintf(lut_name,LUT_PATH_LEN,"%s/%s",lut_searchpath[j],default_lutname[i]);
#endif
            if(!(k=stat(lut_name,&s_buf)))break;
         }
      }
      if(k==-1)RETURN(NO_LUT_FILE);  /* keine Datei gefunden */
   }

   stat(lut_name,&s_buf);
   buflen=s_buf.st_size;
   if(!(buffer=(char *)malloc(buflen)))RETURN(ERROR_MALLOC);
   if(!(lut=fopen(lut_name,"rb"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(rb)");
      FREE(buffer);
      RETURN(FILE_READ_ERROR);
   }
   for(zeile=version=0,ptr=buffer;!feof(lut);){
      if(!fgets(ptr,buflen,lut))RETURN(FILE_READ_ERROR);  /* LUT-Datei zeilenweise einlesen */
      if(!version && !strncmp(buffer,"BLZ Lookup Table/Format 1.0\n",28))version=1;
      if(!version && !strncmp(buffer,"BLZ Lookup Table/Format 1.1\n",28))version=2;
      if(!version && !strncmp(buffer,"BLZ Lookup Table/Format 2.0\n",28))version=3;
      if(++zeile==2)info=ptr;
      if(version==3 && !strncmp(ptr,"DATA\n",5)){  /* Ende des Prologs (LUT 2.0), Nullbyte anhängen */
         *ptr++=0;
         break;
      }
      for(;*ptr;ptr++)buflen--;  /* ptr hinter das Zeilenende setzen, buflen decrement für fgets */
      if(zeile==2){
         if(version>1 && *(ptr-2)=='\\')  /* User-Infozeile vorhanden */
            user_info=ptr;
         else{  /* keine User-Infozeile */
            user_info=(char*)"";
            if(version<3){ /* bei Fileversion 2.0 kommen noch einige Prolog-Daten */
               *ptr++=0;   /* Ende des Prologs (LUT 1.0/1.1), Nullbyte anhängen */
               break;
            }
         }
      }
      if(version==2 && zeile==3){
         *ptr++=0;
         break;
      }
   }
   *ptr++=0;
   if(version_p)*version_p=version;

   if(!prolog_p)  /* keine Rückgabevariable für Prolog => buffer wieder freigeben */
      FREE(buffer);
   else{
         /* sicherstellen, daß in buffer genügend Platz ist für Prolog und Info/User-Info */
      if(s_buf.st_size<(ptr-buffer)*2+10)buffer=(char *)realloc(buffer,(ptr-buffer)*2+10);

         /* Variablen setzen, dann info und user_info kopieren */
      for(sptr=info,info=ptr;*sptr && *sptr!='\n' && *sptr!='\\';)*ptr++=*sptr++;
      *ptr++=0;
      for(sptr=user_info,user_info=ptr;*sptr && *sptr!='\n' && *sptr!='\\';)*ptr++=*sptr++;
      *ptr++=0;

         /* realloc liefert auf einigen Systemen (FreeBSD u.a.) auch bei
          * Verkleinerung des Buffers eine andere Adresse zurück. Daher werden
          * info_p und user_info_p zunächst nur als Offset relativ zu buffer
          * als Basisadresse genommen, und nach dem realloc auf absolute
          * Adressen gesetzt. Dieser Fehler [perl5.11.0 in free(): error: page
          * is already free] tauchte in den Versionen 2.91 und 2.92 in etlichen
          * Tests auf CPAN auf; er dürfte jetzt behoben sein.
          */
      offset1=(info-buffer);
      offset2=(user_info-buffer);
      buffer=(char *)realloc(buffer,(ptr-buffer+10)); /* überflüssigen Speicher wieder freigeben */

         /* nun die absoluten Adressen eintragen */
      *prolog_p=buffer;
      if(info_p)*info_p=buffer+offset1;
      if(user_info_p)*user_info_p=buffer+offset2;
   }
   fclose(lut);
   return OK;
}

/* Funktion copy_lutfile() +§§§1 */
/* ###########################################################################
 * # Die Funktion kopiert eine LUT-Datei, wobei alle obsoleten Blocks        #
 * # weggelassen werden. Falls in einer LUT-Datei mehrere Blocks desselben   #
 * # Typs enthalten sind, wird normalerweise immer der letzte (jüngste)      #
 * # benutzt; diese Funktion säubert somit eine LUT-Datei von Altlasten.     #
 * # Außerdem kann die Anzahl Slots verändert (vergrößert oder verkleinert)  #
 * # werden.                                                                 #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int copy_lutfile(char *old_name,char *new_name,int new_slots)
{
   char *data,*prolog;
   int i,retval,version,last_slot,slotdir[MAX_SLOTS];
   UINT4 slot_cnt,typ,len;
   FILE *lut1=NULL,*lut2;

   if(!init_status&1)init_atoi_table();

      /* Dateiprolog einlesen */
   if((retval=get_lut_info2(old_name,&version,&prolog,NULL,NULL))!=OK)RETURN(retval);
   if(version<3)retval=INVALID_LUT_VERSION;  /* kopieren erst ab LUT-Version 2.0 möglich */
   if(retval==OK && !(lut1=fopen(old_name,"rb"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(rb)");
      retval=FILE_READ_ERROR;
   }
   if(retval==OK)retval=lut_dir(lut1,0,&slot_cnt,NULL,NULL,NULL,NULL,slotdir,NULL);
   if(!new_slots)new_slots=slot_cnt;
   if(retval==OK)retval=create_lutfile_int(new_name,prolog,new_slots,&lut2);  /* neue LUT-Datei anlegen */
   FREE(prolog);
   if(retval!=OK)RETURN(retval);

      /* Liste sortieren, damit jeder Eintrag nur einmal geschrieben wird */
   qsort(slotdir,slot_cnt,sizeof(int),cmp_int);
   for(last_slot=-1,i=0;i<(int)slot_cnt;i++)if((typ=slotdir[i]) && typ!=(UINT4)last_slot){
      read_lut_block_int(lut1,0,typ,&len,&data);
      write_lut_block_int(lut2,typ,len,data);
      FREE(data);
      last_slot=typ;
   }
   fclose(lut1);
   fclose(lut2);
   return OK;
}

/* Funktion kto_check_init2() +§§§1 */
/* ###########################################################################
 * # Diese Funktion ist die Minimalversion zur Initialisierung der           #
 * # konto_check Bibliothek. Sie hat als Parameter nur den Dateinamen (der   #
 * # natürlich auch NULL sein kann); es werden dann alle Blocks des aktuellen#
 * # Sets geladen. Der Rückgabewert ist daher oft -38 (nicht alle Blocks     #
 * # geladen), da die LUT-Datei nicht unbedingt alle Blocks enthält :-).     #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_init2(char *lut_name)
{
   RETURN(kto_check_init_p(lut_name,9,0,0));
}

/* Funktion kto_check_init_p() +§§§1 */
/* ###########################################################################
 * # Dies ist eine etwas vereinfachte Funktion für die Initialisierung der   #
 * # konto_check Bibliothek, die vor allem für den Aufruf aus Perl und PHP   #
 * # gedacht ist. Die Bankleitzahlen, Prüfziffern und Anzahl Filialen werden #
 * # in jedem Fall geladen; außerdem sind noch 10 verschiedene Level mit     #
 * # unterschiedlichen Blocks definiert (lut_set_0 ... lut_set_9), die über  #
 * # einen skalaren Parameter ausgewählt werden können.                      #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_init_p(char *lut_name,int required,int set,int incremental)
{
   int i,j;
   int *rq1,rq2[MAX_SLOTS+1];

   lut_init_level_tmp=required;
   switch(required){
      case  0: rq1=lut_set_0; break;
      case  1: rq1=lut_set_1; break;
      case  2: rq1=lut_set_2; break;
      case  3: rq1=lut_set_3; break;
      case  4: rq1=lut_set_4; break;
      case  5: rq1=lut_set_5; break;
      case  6: rq1=lut_set_6; break;
      case  7: rq1=lut_set_7; break;
      case  8: rq1=lut_set_8; break;
      case  9: rq1=lut_set_9; break;
      default: rq1=lut_set_9; break;
   }
   i=0;
   rq2[i++]=LUT2_BLZ;
   rq2[i++]=LUT2_PZ;
   rq2[i++]=LUT2_FILIALEN;
   for(j=0;i<MAX_SLOTS && rq1[j];)rq2[i++]=rq1[j++];
   rq2[i]=0;
   if(init_status<7)incremental=0; /* noch nicht initialisiert, inkrementell geht nicht */
   RETURN(kto_check_init(lut_name,rq2,NULL,set,incremental));
}

/*  Funktion lut2_status() +§§§1 */
/* ###########################################################################
 * # Diese Funktion gibt das Array  mit den Statuswerten für der Initiali-   #
 * # sierung der LUT-Blocks zurück. Anhand dieses Arrays läßt sich leicht    #
 * # testen, ob ein bestimmter Block initialisiert wurde, und welcher        #
 * # Rückgabewert dabei auftrat.                                             #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int *lut2_status(void)
{
  return lut2_block_status;
}

/* Funktion get_lut_id() +§§§1 */
/* ###########################################################################
 * # Diese Funktion liefert die Datei-ID einer LUT-Datei zurück. Sie wird    #
 * # benutzt, um bei einer inkrementellen Initialisierung zu gewährleisten,  #
 * # daß die Initialisierung auch von demselben Datensatz erfolgt, da        #
 * # ansonsten Inkonsitenzen zu erwarten wären. Die Datei-ID wird für jeden  #
 * # Datensatz im zugehörigen Infoblock gespeichert; im Prolog der Datei     #
 * # findet sich zwar auch eine Datei-ID, dies ist jedoch nur die des ersten #
 * # Datensatzes.                                                            #
 * #                                                                         #
 * # Der Parameter id sollte auf einen Speicherbereich von mindestens 33 Byte#
 * # zeigen. Die Datei-ID wird in diesen Speicher geschrieben.               #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int get_lut_id(char *lut_name,int set,char *id)
{
   char *info,*info1,*info2,*ptr,*dptr;
   int valid,valid1,valid2;

   *id=0;
   info=info1=info2=NULL;
   if(!lut_name || !*lut_name){
      if(lut_id_status==LUT1_SET_LOADED)RETURN(LUT1_FILE_USED);
      if(id)strncpy(id,lut_id,33);
      if(*lut_id)
         return OK;
      else
         RETURN(FALSE);
   }
   else
      switch(set){
         case 0:  /* beide Sets laden, und das gültige nehmen; falls keines gültig ist, das jüngere oder Set 1 */
            lut_info(lut_name,&info1,&info2,&valid1,&valid2);
            if(valid1==LUT1_SET_LOADED)RETURN(LUT1_FILE_USED);
            if(valid1==LUT2_VALID){
               info=info1;
               valid=valid1;
               FREE(info2);
            }
            else if(valid2==LUT2_VALID){
               info=info2;
               valid=valid2;
               FREE(info1);
            }
            else{
               if(valid1==LUT2_NO_LONGER_VALID_BETTER){
                     /* Block 1 jünger als Block 2 */
                  info=info1;
                  valid=valid1;
                  FREE(info2);
               }
               else if(valid2==LUT2_NO_LONGER_VALID_BETTER){
                     /* Block 2 jünger als Block 1 */
                  info=info2;
                  valid=valid2;
                  FREE(info1);
               }
               else{
                  info=info1;
                  valid=valid1;
                  FREE(info2);
               }
            }
            break;

         case 1:  /* nur Set 1 */
            lut_info(lut_name,&info,NULL,&valid,NULL);
            if(valid==LUT1_SET_LOADED)RETURN(LUT1_FILE_USED);
            break;

         case 2:  /* nur Set 2 */
            lut_info(lut_name,NULL,&info,NULL,&valid);
            if(valid==LUT1_SET_LOADED)RETURN(LUT1_FILE_USED);
            break;

         default: /* Fehler */
            FREE(info1);
            FREE(info2);
            RETURN(INVALID_SET);
      }

   if(info && id)for(ptr=info;*ptr;){
      while(*ptr && *ptr++!='\n');
      if(!strncmp(ptr,"Datei-ID (zuf",13)){
         while(*ptr && *ptr++!='\n');
         for(dptr=id;(*dptr=*ptr) && *ptr && *ptr++!='\n';dptr++);
         if(*dptr=='\n')*dptr=0;
         FREE(info);
         return OK;
      }
   }
   FREE(info);
   RETURN(FALSE);
}

/* Funktion lut_init()  */
/* ###########################################################################
 * # Diese Funktion dient dazu, die konto_check Bibliothek zu initialisieren #
 * # und bietet ein (im Gegensatz zu kto_check_init) stark vereinfachtes     #
 * # Benutzerinterface (teilweise entlehnt von kto_check_init_p). Zunächst   #
 * # wird getestet, ob die Bibliothek schon mit der angegebenen Datei (bzw.  #
 * # genauer mit dem gewünschten Datensatz aus der Datei) initialisiert      #
 * # wurde (mittels der Datei-ID aus dem Infoblock des gewählten bzw.        #
 * # gültigen Sets). Falls die Datei-IDs nicht übereinstimmen, wird eine     #
 * # Neuinitialisierung gemacht, andernfalls (nur falls notwendig) eine      #
 * # inkrementelle Initialisierung, um noch benötigte Blocks nachzuladen.    #
 * # Falls schon alle gewünschten Blocks geladen sind, wird nichts gemacht.  #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_init(char *lut_name,int required,int set)
{
   char file_id[36];
   int must_init,incremental;

   must_init=0;
   incremental=1;
   if(get_lut_id(lut_name,set,file_id)!=OK || !*file_id || strcmp(file_id,lut_id)){
      incremental=0;
      if(blz)lut_cleanup();
      must_init=1;
   }
   if(!must_init && required<=lut_init_level)return OK;  /* schon initialisiert */
   RETURN(kto_check_init_p(lut_name,required,set,incremental));
}

/* Funktion kto_check_init() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_init() ist die eigentliche Funktion zur          #
 * # Initialisierung der konto_check Bibliothek; alle abgeleiteten Funktionen#
 * # greifen auf diese Funktion zurück. Sie ist sehr flexibel, aber beim     #
 * # Glue Code für andere Sprachen machen die Parameter required (INT-Array  #
 * # der gewünschten Blocks) und status (Pointer auf ein INT-Array, in dem   #
 * # der Status des jeweiligen Blocks zurückgegeben wird) manchmal etwas     #
 * # Probleme; daher gibt es noch einige andere Initialisierungsfunktionen   #
 * # mit einfacherem Aufrufinterface, wie lut_init() oder kto_check_init_p().#
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */
DLL_EXPORT int kto_check_init(char *lut_name,int *required,int **status,int set,int incremental)
{
   char *ptr,*dptr,*data,*eptr,*prolog,*info,*user_info,*hs=NULL,*info1,*info2,*ci=NULL,name_buffer[LUT_PATH_LEN];
   int b,h,i,j,k,x,y,v1,v2,retval,release_data,alles_ok,slotdir[MAX_SLOTS],*iptr,*rptr,xrequired[MAX_SLOTS],own_iban_2;
   UINT4 len,typ,typ1,slot_cnt;
   FILE *lut;
   struct stat s_buf;

   set_offset=0;
   if(!required)required=lut_set_9;   /* falls nichts angegeben, alle Felder einlesen */
   own_iban_2=0;

      /* falls schon einmal initialisiert wurde (BLZ und PZ-Methoden gelesen),
       * eine Millisekunde warten, damit evl. laufende Tests sicher beendet
       * sind.
       */
   if((init_status&6)==6)usleep(1000);
   if(!incremental){
      lut_cleanup(); /* falls nicht inkrementelles init, alle bisher allokierten Variablen freigeben */
      if(!(init_status&1))init_atoi_table();
      init_status=1; /* init_status löschen, nur Variablen */
   }
      /* current_lut_level und lut_init_level werden in lut_cleanup() aufgeräumt, deshalb werden sie erst hier gesetzt. */
   if(lut_init_level_tmp>=0)current_lut_level=lut_init_level=lut_init_level_tmp;
   lut_init_level_tmp=-1;

   INITIALIZE_WAIT;     /* zunächst testen, ob noch eine andere Initialisierung läuft (z.B. in einem anderen Thread) */
   init_in_progress=1;  /* Lockflag für Tests und Initialierung setzen */
   init_status|=8;      /* init_status wird bei der Prüfung getestet */
   usleep(10);
   if(init_status&16){
      init_in_progress=0;        /* Flag für Aufräumaktion rücksetzen */
      RETURN(INIT_FATAL_ERROR);   /* Aufräumaktion parallel gelaufen; alles hinwerfen (aktueller Status unklar) */
   }

      /* falls keine LUT-Datei angegeben wurde, die Suchpfade und Defaultnamen durchprobieren */
   if(!lut_name || !*lut_name){
      for(j=0,k=-1;j<lut_searchpath_cnt && k==-1;j++){
         for(i=0,lut_name=name_buffer;i<lut_name_cnt;i++){
#if _WIN32>0
            snprintf(lut_name,LUT_PATH_LEN,"%s\\%s",lut_searchpath[j],default_lutname[i]);
#else
            snprintf(lut_name,LUT_PATH_LEN,"%s/%s",lut_searchpath[j],default_lutname[i]);
#endif
            if(!(k=stat(lut_name,&s_buf)))break;
         }
      }
      if(k==-1){
         init_status=init_in_progress=0;
         RETURN(NO_LUT_FILE);  /* keine Datei gefunden */
      }
   }
   if(status)*status=lut2_block_status;   /* Rückgabe des Statusarrays, falls gewünscht */

      /* Info-Block holen und merken */
   if((retval=lut_info(lut_name,&info1,&info2,&v1,&v2))==OK){
      if(!set){
         if(v1==LUT2_VALID){
            lut_id_status=v1;
            set=1;
         }
         else if(v2==LUT2_VALID){
            lut_id_status=v2;
            set=2;
         }
         else if(v1==LUT2_NO_VALID_DATE){
            lut_id_status=v1;
            set=1;
         }
         else if(v2==LUT2_NO_VALID_DATE){
            lut_id_status=v2;
            set=2;
         }
         else{
            lut_id_status=v1;
            set=1;
         }
      }
      else
         lut_id_status=OK;
      if(set==1){
         if(incremental)
            ci=info1;
         else{
            FREE(current_info);
            current_info=info1;
         }
         FREE(info2);
         set_offset=0;
      }
      else{
         if(incremental)
            ci=info2;
         else{
            FREE(current_info);
            current_info=info2;
         }
         FREE(info1);
         set_offset=SET_OFFSET;
      }
      if(!current_info || (incremental && !ci)){
         FREE(ci);
         init_in_progress=0;
         init_status&=7;
         RETURN(LUT2_BLOCK_NOT_IN_FILE);
      }

      /* Beim inkrementellen Initialisieren den Prolog der initial
       * geladenen LUT-Datei (in current_info) mit dem der aktuell
       * angegebenen Datei (in ci) vergleichen. Die beiden müssen gleich
       * sein, ansonsten erfolgt ein Abbruch der Initialisierung, da bei
       * einer Initialisierung aus verschiedenen Dateien Inkonsistenzen
       * zu erwarten sind.
       */
      if(incremental){
         if(strcmp(ci,current_info)){
            init_in_progress=0;
            init_status&=7;
            FREE(ci);
            RETURN(INCREMENTAL_INIT_FROM_DIFFERENT_FILE);
         }
      }
      else{
         current_info_len=strlen(current_info);
         for(ptr=current_info,current_v1=current_v2=0;*ptr && *ptr!='\n' && !isdigit(*ptr);ptr++);
         if(*ptr && *ptr!='\n'){
            current_v1=strtoul(ptr,NULL,10);             /* Anfangsdatum der Gültigkeit */
            if(*ptr && *ptr!='\n'){
               while(*ptr && *ptr!='\n' && *ptr++!='-'); /* Endedatum suchen */
               if(*ptr)current_v2=strtoul(ptr,NULL,10);  /* Endedatum der Gültigkeit */
            }
         }
      }
      FREE(ci);
      for(ptr=current_info,*lut_id=0;*ptr;){  /* nun die ID der LUT-Datei merken */
         while(*ptr && *ptr++!='\n');
         if(!strncmp(ptr,"Datei-ID (zuf",13)){
            while(*ptr && *ptr++!='\n');
               /* LUT-ID in den statischen Buffer kopieren */
            for(dptr=lut_id;(*dptr=*ptr) && *ptr && *ptr++!='\n';dptr++);
            if(*dptr=='\n')*dptr=0;
         }
      }
   }
   else{
      if(retval==FILE_READ_ERROR || retval==INVALID_LUT_FILE){
         init_status=init_in_progress=0;
         return retval;
      }
      if(incremental)RETURN(INCREMENTAL_INIT_NEEDS_INFO);
      current_info=NULL;
      *lut_id=0;
      current_info_len=current_v1=current_v2=0;
      if(!set)set=1; /* kein Gültigkeitsdatum vorhanden, defaultmäßig primären Datensatz nehmen */
   }
   if(!incremental){ /* der folgende Teil darf nicht bei incremental gemacht werden, da dieses u.U. current_lutfile benutzt */
      if(current_lutfile)FREE(current_lutfile);
      if(!(current_lutfile=(char *)malloc(strlen(lut_name)+10)))return ERROR_MALLOC;
      strcpy(current_lutfile,lut_name);
   }
   current_lut_set=set;

      /* zunächst muß zwingend die die BLZ und die Anzahl der Filialen
       * eingelesen werden (wegen der Anzahl Datensätze). Außerdem wird der
       * Block mit Änderungen (für das Löschkennzeichen) und die
       * Prüfziffermethoden immer geladen.
       */
   *xrequired=LUT2_BLZ+set_offset;
   *(xrequired+1)=LUT2_FILIALEN+set_offset;
   *(xrequired+2)=LUT2_PZ+set_offset;
   *(xrequired+3)=LUT2_AENDERUNG+set_offset;
   for(iptr=required,rptr=xrequired+4;*iptr;iptr++)
      if(*iptr>SET_OFFSET)
         *rptr++=*iptr-SET_OFFSET+set_offset;
      else
         *rptr++=*iptr+set_offset;
   *rptr=0;

   if(!incremental){ /* dieser Teil wird nur beim ersten Einlesen benötigt */

         /* Prolog und Infozeilen der Datei holen und nach own_buffer kopieren */
      if((retval=get_lut_info2(lut_name,&lut_version,&prolog,&info,&user_info))!=OK){
         FREE(prolog);
         init_in_progress=0;
         RETURN(retval);
      }
      FREE(own_buffer);
      own_buffer=(char *)malloc(strlen(prolog)+strlen(info)+strlen(user_info)+10);
      for(lut_prolog=optr=own_buffer,ptr=prolog;(*optr++=*ptr++););
      for(ptr=info,lut_sys_info=optr;(*optr++=*ptr++););
      for(ptr=user_info,lut_user_info=optr;(*optr++=*ptr++););
      FREE(prolog);
      if(lut_version<3){
         retval=read_lut(lut_name,&lut2_cnt_hs);
         if(retval==OK){
            lut2_cnt=lut2_cnt_hs;
            lut2_block_status[LUT2_BLZ]=lut2_block_status[LUT2_PZ]=OK;
            init_status|=6;
            init_status&=7;
            init_in_progress=0;
            RETURN(LUT1_SET_LOADED);
         }
         else{
            init_in_progress=0;
            RETURN(retval);
         }
      }
   }

   if(!(lut=fopen(lut_name,"rb"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(rb)");
      init_in_progress=0;
      RETURN(FILE_READ_ERROR);
   }
   if((retval=lut_dir(lut,0,&slot_cnt,NULL,NULL,NULL,NULL,slotdir,NULL))!=OK){
      fclose(lut);
      init_in_progress=0;
      RETURN(retval);
   } 
   for(rptr=xrequired,alles_ok=1;*rptr;){  /* versuchen, die gewünschten Blocks einzulesen */
      typ=*rptr++;
      if(typ>SET_OFFSET)
         typ1=typ-SET_OFFSET;
      else
         typ1=typ;
      if(lut2_block_status[typ]==OK)continue;   /* jeden Block nur einmal einlesen */
      retval=read_lut_block_int(lut,0,typ,&len,&data);

      switch(retval){
         case LUT_CRC_ERROR:
         case LUT2_Z_BUF_ERROR:
         case LUT2_Z_MEM_ERROR:
         case LUT2_Z_DATA_ERROR:

               /* Fehler bei einem Block; eintragen, dann weitere Blocks einlesen */
            lut2_block_status[typ]=lut2_block_status[typ1]=retval;
            alles_ok=lut2_block_len[typ]=0;
            lut2_block_data[typ]=NULL;
            lut_blocks_missing++;
            continue;

         case LUT2_BLOCK_NOT_IN_FILE:

               /* falls die IBAN Blackliste nicht enthalten ist, im anderen Block nachsehen
                * und evl. von da nachladen (die Liste ändert sich nicht so oft).
                */
            if(typ==LUT2_OWN_IBAN){
               if(!own_iban_2){
                  own_iban_2=1;  /* Flag, daß schon ein Versuch mit dem Block gemacht wurde (sonst gibt es eine Endlosschleife) */
                  *--rptr=LUT2_2_OWN_IBAN;
                  continue;
               }
               else
                  lut_blocks_missing++;
            }
            if(typ==LUT2_2_OWN_IBAN){
               if(!own_iban_2){
                  own_iban_2=1;
                  *--rptr=LUT2_OWN_IBAN;
                  continue;
               }
               else
                  lut_blocks_missing++;
            }

               /* Sonderfall LUT2_NAME und LUT2_NAME_KURZ: die beiden Blocks
                * können auch gemeinsam in LUT2_NAME_NAME_KURZ enthalten sein;
                * versuchen, diesen Block einzulesen; umgekehrt genauso.
                */
            if(typ==LUT2_NAME_NAME_KURZ){
               *--rptr=LUT2_NAME_KURZ; /* beim nächsten Block den Kurznamen einlesen */
               typ=typ1=LUT2_NAME;
               FREE(data);
               i=read_lut_block_int(lut,0,LUT2_NAME,&len,&data);
               if(i==OK){  /* was gefunden; eintragen und Block verarbeiten */
                  lut2_block_status[typ]=lut2_block_status[typ1]=i;
                  lut2_block_len[typ]=lut2_block_len[typ1]=len;
                  lut2_block_data[typ]=lut2_block_data[typ1]=data;
                  break;
               }
               else
                  lut_blocks_missing++;
            }
            if(typ==LUT2_2_NAME_NAME_KURZ){ /* wie oben, nur sekundärer Datenblock */
               *--rptr=LUT2_2_NAME_KURZ; /* beim nächsten Block den Kurznamen einlesen */
               typ=LUT2_2_NAME;
               typ1=LUT2_NAME;
               FREE(data);
               i=read_lut_block_int(lut,0,LUT2_2_NAME,&len,&data);
               if(i==OK){  /* was gefunden; eintragen und Block verarbeiten */
                  lut2_block_status[typ]=lut2_block_status[typ1]=i;
                  lut2_block_len[typ]=lut2_block_len[typ1]=len;
                  lut2_block_data[typ]=lut2_block_data[typ1]=data;
                  break;
               }
               else
                  lut_blocks_missing++;
            }
            if(typ==LUT2_NAME || typ==LUT2_NAME_KURZ){
               FREE(data);
               i=read_lut_block_int(lut,0,LUT2_NAME_NAME_KURZ,&len,&data);
               if(i==OK){  /* was gefunden; Typ ändern, dann weiter wie bei OK */
                  typ=typ1=LUT2_NAME_NAME_KURZ;
                  lut2_block_status[typ]=lut2_block_status[typ1]=i;
                  lut2_block_len[typ]=lut2_block_len[typ1]=len;
                  lut2_block_data[typ]=lut2_block_data[typ1]=data;
                  break;
               }
               else
                  lut_blocks_missing++;
            }
            if(typ==LUT2_2_NAME || typ==LUT2_2_NAME_KURZ){
               FREE(data);
               i=read_lut_block_int(lut,0,LUT2_2_NAME_NAME_KURZ,&len,&data);
               if(i==OK){  /* was gefunden; Typ ändern, dann weiter wie bei OK */
                  typ=LUT2_2_NAME_NAME_KURZ;
                  typ1=LUT2_NAME_NAME_KURZ;
                  lut2_block_status[typ]=lut2_block_status[typ1]=i;
                  lut2_block_len[typ]=lut2_block_len[typ1]=len;
                  lut2_block_data[typ]=lut2_block_data[typ1]=data;
                  break;
               }
               else
                  lut_blocks_missing++;
            }
               /* Fehler bei dem Block; eintragen, dann weitere Blocks einlesen */
            lut2_block_status[typ]=lut2_block_status[typ1]=retval;

               /* für fehlendes LUT2_OWN_IBAN und LUT2_FILIALEN (das kommt vor,
                * wenn in der LUT-Datei nur die Hauptstellen enthalten sind)
                * keine Warnung erzeugen. Bei LUT2_IBAN_REGEL gibt es jetzt
                * (seit Version 5.2) eine Warnung, da sie für die
                * IBAN-Funktionen mittlerweile ziemlig unerläßlich ist. Falls
                * LUT2_OWN_IBAN nicht geladen werden konnte, wird der Block in
                * der Funktion lut_blocks() als nicht geladen angegeben; bei
                * lut_init() wird dagegen OK zurückgegeben.
                */
            if(typ!=LUT2_OWN_IBAN && typ!=LUT2_2_OWN_IBAN && typ!=LUT2_FILIALEN && typ!=LUT2_2_FILIALEN){
               alles_ok=0;
               lut_blocks_missing++;
            }
            lut2_block_len[typ]=lut2_block_len[typ1]=0;
            lut2_block_data[typ]=lut2_block_data[typ1]=NULL;
            continue;

         case KTO_CHECK_UNSUPPORTED_COMPRESSION:
         case LUT2_FILE_CORRUPTED:
         case ERROR_MALLOC:
               /* fatale Fehler: Einlesen abbrechen, alles aufräumen */
            lut2_block_status[typ]=lut2_block_status[typ1]=retval;
            alles_ok=lut2_block_len[typ]=lut2_block_len[typ1]=0;
            lut2_block_data[typ]=lut2_block_data[typ1]=NULL;
            init_in_progress=0;
            fclose(lut);
            FREE(info1);
            FREE(info2);
            lut_cleanup();
            RETURN(retval);

         case OK:
            lut2_block_status[typ]=lut2_block_status[typ1]=OK;
            lut2_block_len[typ]=lut2_block_len[typ1]=len;
            lut2_block_data[typ]=lut2_block_data[typ1]=data;
            break;
      }

         /* nun werden die internen Blocks verarbeitet */
      switch(typ){
         case LUT2_BLZ:  /* Bankleitzahl */
         case LUT2_2_BLZ:
            release_data=1;
            ptr=data;
            C2UI(lut2_cnt_hs,ptr);  /* Anzahl der Datensätze (nur Hauptstellen) holen */
            C2UI(lut2_cnt,ptr);     /* Anzahl der Datensätze (gesamt) holen */
            init_status|=2;

            FREE(blz);
            FREE(hash);
            if(!(blz=(int *)calloc(lut2_cnt_hs+1,sizeof(int)))
                  || (!startidx && !(startidx=(int *)calloc(lut2_cnt_hs,sizeof(int))))  /* Index der Hauptstelle in den großen Arrays */
                  || (!hs_idx && !(hs_idx=(int *)calloc(lut2_cnt,sizeof(int))))   /* reziprok zu startidx */
                  || !(hash=(short int *)calloc(sizeof(short),HASH_BUFFER_SIZE)))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               for(i=0,eptr=data+len;ptr<eptr && i<lut2_cnt_hs;i++){
                  startidx[i]=i;
                  j=UI *ptr++;
                  switch(j){
                     case 254:
                        C2UI(j,ptr);
                        blz[i]=blz[i-1]+j;
                        break;
                     case 255:
                        C2UL(j,ptr);
                        blz[i]=j;
                        break;
                     default:
                        blz[i]=blz[i-1]+j;
                        break;
                  }
               }
               blz[lut2_cnt_hs]=999999999;
               for(i=0;i<HASH_BUFFER_SIZE;i++)hash[i]=lut2_cnt_hs;
               for(i=0;i<lut2_cnt_hs;i++){
                  b=blz[i];      /* b BLZ, h Hashwert */
                  k=b%10; h= hx8[k]; b/=10;
                  k=b%10; h+=hx7[k]; b/=10;
                  k=b%10; h+=hx6[k]; b/=10;
                  k=b%10; h+=hx5[k]; b/=10;
                  k=b%10; h+=hx4[k]; b/=10;
                  k=b%10; h+=hx3[k]; b/=10;
                  k=b%10; h+=hx2[k]; b/=10;
                  k=b%10; h+=hx1[k];
                  while(hash[h]!=lut2_cnt_hs)h++;
                  hash[h]=i;
               }
            }
            break;

         case LUT2_FILIALEN:  /* Anzahl Filialen */
         case LUT2_2_FILIALEN:
            release_data=1;
            FREE(filialen);
            if(!(filialen=(int *)calloc(len,sizeof(int))) || (!startidx_r && !(startidx_r=(int *)calloc(lut2_cnt,sizeof(int)))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               for(i=j=x=0,ptr=data,eptr=data+len;i<(int)len;i++){
                  startidx[i]+=j;   /* j ist nur ein Inkrement, startidx[] wurde oben mit i initialisiert */
                  filialen[i]=UI *ptr++;
                  for(y=0;y<filialen[i];y++){
                     hs_idx[x]=startidx[i]; /* Hauptstellen-Index für alle Filialen der Bank setzen */
                     startidx_r[x++]=i;     /* Rückverweis aus den großen Arrays ins BLZ- und Prüfziffer-Array */
                  }
                  j+=filialen[i]-1;
               }
            }
            break;

            /* Der folgende Block enthält entweder die Banken, für die keine
             * IBAN-Berechnung gemacht werden soll (entweder aus der Datei
             * CONFIG.INI des SEPA Account Converters der Sparkassen, oder eine
             * andere Liste, z.B. von www.iban-service-portal.de). Der Block
             * ist u.U. nicht in der LUT-Datei enthalten. Dies wird jedoch
             * nicht als Fehler angesehen, sondern einfach ignoriert.
             *
             * Die Daten für diesen Block können aus der Datei CONFIG.INI des
             * Sepa-Account-Converters der Sparkassen (sepa_account_converter.msi)
             * gewonnen werden. Dieses Programm wird vierteljährlich
             * aktualisiert; der Gülitigkeitszeitraum entspricht dem der
             * Bundesbankdatei (das war nur notwendig, solange die IBAN-Regeln
             * noch nicht definiert waren). Falls die IBAN-Regeln definiert sind,
             * wird diese Liste ignoriert.
             *
             * Eine andere Variante ist die Ausschlußliste von
             * www.iban-service-portal.de. Im Anhang des Benutzerhandbuchs
             * werden einige Banken aufgeführt, für die keine Berechnung
             * gemacht werden soll. Das Handbuch gibt es unter
             * https://www.iban-service-portal.de/Benutzerhandbuch_IBAN_Service_Portal.pdf
             * (abgerufen 13.7.13). Zur Unterscheidung von CONFIG.INI muß dabei
             * eine "BLZ" 2718281 (siebenstellig!) in der Liste vorhanden sein.
             * 
             * Diese Daten ändern sich weniger oft und können daher über einen
             * längeren Zeitraum benutzt werden.
             *
             * Aktuell (zum März 2014) ist die Ausschlußliste leer, der Block
             * wird nicht weiter verwendet.
             */
         case LUT2_OWN_IBAN:
         case LUT2_2_OWN_IBAN:
            release_data=1;
            FREE(own_iban);
            ptr=data;
            C2UL(own_iban_cnt,ptr);
            if(!(own_iban=(int *)calloc(own_iban_cnt,sizeof(int))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else
               for(i=0;i<own_iban_cnt;i++)C2UL(own_iban[i],ptr);
            break;

         case LUT2_NAME:  /* Bezeichnung des Kreditinstitutes (ohne Rechtsform) */
         case LUT2_2_NAME:
            release_data=0;
            FREE(name);
            if(!(name=(char **)calloc(lut2_cnt,sizeof(char*))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               FREE(name_data);
               if(keep_raw_data_flag){
                  name_raw=data;
                  name_raw_len=len;
               }
               if(encoding==1)
                  current_encoding=1;
               else if((retval=convert_encoding(&data,&len))<=0)
                  return retval;
               for(i=0,name_data=ptr=data,eptr=data+len;ptr<eptr && i<lut2_cnt;i++){
                  if(*ptr==1)
                     hs=name[i]=++ptr;
                  else if(*ptr)
                     name[i]=ptr;
                  else
                     name[i]=hs;
                  while(*ptr++ && ptr<eptr);
               }
            }
            break;

         case LUT2_NAME_KURZ:  /* Kurzbezeichnung des Kreditinstitutes mit Ort (ohne Rechtsform) */
         case LUT2_2_NAME_KURZ:
            release_data=0;
            FREE(name_kurz);
            if(!(name_kurz=(char **)calloc(lut2_cnt,sizeof(char*))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               FREE(name_kurz_data);
               FREE(name_kurz_raw);
               if(keep_raw_data_flag){
                  name_kurz_raw=data;
                  name_kurz_raw_len=len;
               }
               if(encoding==1)
                  current_encoding=1;
               else if((retval=convert_encoding(&data,&len))<=0)
                  return retval;
               for(i=0,name_kurz_data=ptr=data,eptr=data+len;ptr<eptr && i<lut2_cnt;i++){
                  name_kurz[i]=ptr;
                  while(*ptr++ && ptr<eptr);
               }
            }
            break;

        case LUT2_NAME_NAME_KURZ:  /* Name und Kurzname zusammen */
        case LUT2_2_NAME_NAME_KURZ:
            release_data=0;
            FREE(name);
            FREE(name_kurz);
            if(!(name=(char **)calloc(lut2_cnt,sizeof(char*))) || !(name_kurz=(char **)calloc(lut2_cnt,sizeof(char*))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               if(name_name_kurz_data==name_name_kurz_raw)name_name_kurz_raw=NULL;
               FREE(name_name_kurz_data);
               FREE(name_name_kurz_raw);
               if(keep_raw_data_flag){
                  name_name_kurz_raw=data;
                  name_name_kurz_raw_len=len;
               }
               if(encoding==1)
                  current_encoding=1;
               else if((retval=convert_encoding(&data,&len))<=0)
                  return retval;
               for(i=0,name_name_kurz_data=ptr=data,eptr=data+len;ptr<eptr && i<lut2_cnt;i++){
                  if(*ptr==1)
                     hs=name[i]=++ptr;
                  else if(*ptr)
                     name[i]=ptr;
                  else
                     name[i]=hs;
                  while(ptr<eptr && *ptr++);
                  name_kurz[i]=ptr;
                  while(ptr<eptr && *ptr++);
               }
               lut2_block_status[LUT2_NAME]=OK;
               lut2_block_status[LUT2_NAME_KURZ]=OK;
            }
            break;

         case LUT2_PLZ:  /* Postleitzahl */
         case LUT2_2_PLZ:
            release_data=1;
            FREE(plz);
            if(!(plz=(int *)calloc(len/3,sizeof(int)))){
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            }
            else{
               for(i=0,ptr=data,eptr=data+len;ptr<eptr;i++){
                  C2UM(j,ptr);
                  plz[i]=j;
               }
            }
            break;

         case LUT2_ORT:  /* Ort */
         case LUT2_2_ORT:
            release_data=0;
            FREE(ort);
            if(!(ort=(char **)calloc(lut2_cnt,sizeof(char*))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               FREE(ort_data);
               FREE(ort_raw);
               if(keep_raw_data_flag){
                  ort_raw=data;
                  ort_raw_len=len;
               }
               if(encoding==1)
                  current_encoding=1;
               else if((retval=convert_encoding(&data,&len))<=0)
                  return retval;
               for(i=0,ort_data=ptr=data,eptr=data+len;ptr<eptr && i<lut2_cnt;i++){
                  ort[i]=ptr;
                  while(*ptr++ && ptr<eptr);
               }
            }
            break;

         case LUT2_IBAN_REGEL:  /* IBAN-Regel */
         case LUT2_2_IBAN_REGEL:
            release_data=1;
            FREE(iban_regel);
            if(!(iban_regel=(int *)calloc(lut2_cnt,sizeof(int)))){
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            }
            else{
               for(i=0,ptr=data,eptr=data+len;i<lut2_cnt;i++){
                  C2UM(j,ptr);
                  iban_regel[i]=j;
               }
            }
            break;

         case LUT2_PAN:  /* Institutsnummer für PAN */
         case LUT2_2_PAN:
            release_data=1;
            FREE(pan);
            if(!(pan=(int *)calloc(lut2_cnt,sizeof(int)))){
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            }
            else{
               for(i=0,ptr=data,eptr=data+len;i<lut2_cnt;i++){
                  C2UM(j,ptr);
                  pan[i]=j;
               }
            }
            break;

         case LUT2_BIC:  /* Bank Identifier Code - BIC */
         case LUT2_2_BIC:
            release_data=1;
            FREE(bic);
            FREE(bic_h);
            FREE(bic_buffer);
            if(!(bic_buffer=(char *)calloc(lut2_cnt+10,12)) || !(bic=(char **)calloc(lut2_cnt+10,sizeof(char*)))
                  || !(bic_h=(char **)calloc(lut2_cnt+10,sizeof(char**)))){
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            }
            else{
               for(i=0,ptr=data,eptr=data+len,dptr=bic_buffer;ptr<eptr && i<lut2_cnt;i++){
                  bic[i]=((char *)(dptr-bic_buffer));
                  if(!*ptr){  /* Leerstring einsetzen (später) */
                     bic[i]=NULL;
                     ptr++;
                  }
                  else if(*ptr==1){  /* Flag für Landkennzeichen != DE; komplett kopieren */
                     for(j=0,ptr++;j<11;j++)*dptr++=*ptr++;
                  }
                  else{
                     *dptr++=*ptr++;
                     *dptr++=*ptr++;
                     *dptr++=*ptr++;
                     *dptr++=*ptr++;
                     *dptr++='D';
                     *dptr++='E';
                     *dptr++=*ptr++;
                     *dptr++=*ptr++;
                     *dptr++=*ptr++;
                     *dptr++=*ptr++;
                     *dptr++=*ptr++;
                  }
                  *dptr++=0;
               }
               bic_buffer=(char *)realloc(bic_buffer,(size_t)(dptr-bic_buffer)+10);

                  /* die Schleife darf erst ab 1 laufen, da der Offset für die
                   * Bundesbank (in bic[0]) 0 ist. bic[0] und bic_h[0] muß
                   * manuell auf den Anfang von bic_buffer gesetzt werden.
                   */
               bic[0]=bic_h[0]=bic_buffer;
               for(j=1;j<i;j++){
                  if(!bic[j])   /* Leerstring */
                     bic[j]=(char*)"           ";
                  else  /* Adresse anpassen */
                     bic[j]=(char*)(bic_buffer+(unsigned long)bic[j]);
                  bic_h[j]=bic[hs_idx[j]];
               }
            }
            break;

         case LUT2_PZ:  /* Kennzeichen für Prüfzifferberechnungsmethode */
         case LUT2_2_PZ:
            release_data=1;
            FREE(pz_methoden);
            if(!(pz_methoden=(int *)calloc(len,sizeof(int))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               for(i=0,ptr=data,eptr=data+len;ptr<eptr;i++)pz_methoden[i]=UI *ptr++;
               init_status|=4;
            }
            break;

         case LUT2_NR:  /* Nummer des Datensatzes */
         case LUT2_2_NR:
            release_data=1;
            FREE(bank_nr);
            if(!(bank_nr=(int *)calloc(len,sizeof(int))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               for(i=0,ptr=data,eptr=data+len;ptr<eptr;i++){
                  C2UM(j,ptr);
                  bank_nr[i]=j;
               }
            }
            break;

         case LUT2_AENDERUNG:  /* Änderungskennzeichen */
         case LUT2_2_AENDERUNG:
            release_data=1;
            FREE(aenderung);
            if(!(aenderung=(char *)calloc(len,1)))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else
               for(ptr=data,dptr=aenderung,eptr=data+len;ptr<eptr;)*dptr++=*ptr++;
            break;

         case LUT2_LOESCHUNG:  /* Hinweis auf eine beabsichtigte Bankleitzahllöschung */
         case LUT2_2_LOESCHUNG:
            release_data=1;
            FREE(loeschung);
            if(!(loeschung=(char *)calloc(len,1)))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else
               for(ptr=data,dptr=loeschung,eptr=data+len;ptr<eptr;)*dptr++=*ptr++;
            break;

         case LUT2_NACHFOLGE_BLZ:  /* Hinweis auf Nachfolge-Bankleitzahl */
         case LUT2_2_NACHFOLGE_BLZ:
            release_data=1;
            FREE(nachfolge_blz);
            if(!(nachfolge_blz=(int *)calloc(len/4,sizeof(int))))
               lut2_block_status[typ]=lut2_block_status[typ1]=ERROR_MALLOC;
            else{
               for(i=0,ptr=data,eptr=data+len;ptr<eptr;i++){
                  C2UL(j,ptr);
                  nachfolge_blz[i]=j;
               }
            }
            break;

         default :   /* Benutzer-Datenblock: nicht verarbeiten, Daten stehenlassen */
            release_data=0;
            continue;   /* nächsten Block einlesen */
      }
      if(release_data){
         FREE(data); /* die (Roh-)Daten werden nicht mehr benötigt, Speicher freigeben */
         lut2_block_len[typ]=lut2_block_len[typ1]=0;
         lut2_block_data[typ]=lut2_block_data[typ1]=NULL;
      }
   }
   fclose(lut);
   init_in_progress=0;
   init_status&=7;

   if(alles_ok)
      return OK;  /* alle Blocks geladen */
   else
      switch(lut_valid()){
         case LUT2_VALID:
         case LUT2_NO_VALID_DATE:
            return LUT2_PARTIAL_OK;   /* Warnung bzw. Fehler/negativ (angeforderte Blocks fehlen => ret=-38) */
         case LUT2_NO_LONGER_VALID:
            return LUT2_NO_LONGER_VALID_PARTIAL_OK;
         case LUT2_NOT_YET_VALID:
            return LUT2_NOT_YET_VALID_PARTIAL_OK;
         default:
            return LUT2_PARTIAL_OK;
      }
}

/* Funktion lut_blocks() +§§§1 */
/* ############################################################################
 * # Die Funktion lut_blocks() testet die Status-Arrays, welche Blocks der    #
 * # LUT-Datei richtig geladen wurden, und bei welchen Fehler auftraten.      #
 * # Außerdemm läßt sich mit dieser Funktion der zur Initialisierung benutzte #
 * # Dateiname ermitteln.                                                     #
 * #                                                                          #
 * # Parameter:                                                               #
 * #   mode:              Dieser Parameter (1...3) bestimmt das Ausgabeformat #
 * #   lut_filename:      Dateiname der LUT-Datei                             #
 * #   lut_blocks_ok:     Liste der Blocks, die fehlerfrei geladen wurden     #
 * #   lut_blocks_fehler: Liste der Blocks, bei denen Fehler auftraten        #
 * #                                                                          #
 * # Für die Rückgabeparameter lut_filename, lut_blocks_ok sowie              #
 * # lut_blocks_fehler wird per malloc() Speicher allokiert; dieser muß von   #
 * # der aufrufenden Funktion wieder freigegeben werden.                      #
 * #                                                                          #
 * # mögliche Rückgabewerte:                                                  #
 * #   LUT2_NOT_INITIALIZED  die Bibliothek wurde noch nicht initialisiert    #
 * #   ERROR_MALLOC          Fehler beim Speicher allokieren                  #
 * #   LUT2_BLOCKS_MISSING   bei einigen Blocks traten Fehler auf             #
 * #   OK                    alle Blocks erfolgreich geladen                  #
 * #                                                                          #
 * # Copyright (C) 2013 Michael Plugge <m.plugge@hs-mannheim.de>              #
 * ############################################################################
 */
DLL_EXPORT int lut_blocks(int mode,char **lut_filename,char **lut_blocks_ok,char **lut_blocks_fehler)
{
   char **startptr,*ptr,*dptr;
   int i;

   if(lut_filename)*lut_filename=NULL;
   if(lut_blocks_ok)*lut_blocks_ok=NULL;
   if(lut_blocks_fehler)*lut_blocks_fehler=NULL;

   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   switch(mode){
      default:
      case 1:
         startptr=(char**)lut_block_name1;
         break;
      case 2:
         startptr=(char**)lut_block_name2;
         break;
      case 3:
         startptr=(char**)lut2_feld_namen;
         break;
   }

   if(lut_filename){
      if(!current_lutfile)return LUT2_NOT_INITIALIZED;
      if(!(*lut_filename=dptr=(char *)malloc(strlen(current_lutfile)+4)))return ERROR_MALLOC;
      strcpy(dptr,current_lutfile);
   }
   if(lut_blocks_fehler){
      if(!(*lut_blocks_fehler=dptr=(char *)malloc(lut_blocklen_max+4)))return ERROR_MALLOC;
      if(!lut_blocks_missing)
         *dptr=0;
      else{
         for(i=0;i<SET_OFFSET;i++)if(lut2_block_status[i+set_offset]<0){
            for(ptr=startptr[i+set_offset];(*dptr=*ptr++);dptr++);
            *dptr++=',';
            *dptr++=' ';
         }
         *(dptr-2)=0;
      }
   }
   if(lut_blocks_ok){
      if(!(*lut_blocks_ok=dptr=(char *)malloc(lut_blocklen_max+4)))return ERROR_MALLOC;
      for(i=0;i<SET_OFFSET;i++)if(lut2_block_status[i+set_offset]==OK){
         for(ptr=startptr[i+set_offset];(*dptr=*ptr++);dptr++);
         *dptr++=',';
         *dptr++=' ';
      }
      *(dptr-2)=0;
   }
   if(lut_blocks_missing)
      return LUT2_BLOCKS_MISSING;
   else
      return OK;
}


/* Funktion lut_blocks_id() +§§§1 */
/* ############################################################################
 * # Die Funktion lut_blocks_id() entspricht der Funktion lut_blocks(); die   #
 * # Rückgabe erfolgt jedoch per Handle. Die Funktion ist vor allem für die   #
 * # Windows-DLL gedacht, da der angeforderte Speicher wieder freigegeben     #
 * # werden muß. Rückgabewerte und Parameter s.o. Die Parameter lut_blocks_ok #
 * # und lut_blocks_fehler können mit der Funktion kc_id2ptr() in einen       #
 * # String umgewandelt werden; mittels kc_id_free() kann der allokierte      #
 * # Speicher wieder freigegeben werden.                                      #
 * #                                                                          #
 * # Diese Funktion unterstützt keine optionalen Parameter, d.h. die drei     #
 * # Variablen lut_filename, lut_blocks_ok und lut_blocks_fehler müssen immer #
 * # angegeben werden; eine Übergabe von NULL führt zu einer access violation.#
 * #                                                                          #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>              #
 * ############################################################################
 */
DLL_EXPORT int lut_blocks_id(int mode,int *lut_filename,int *lut_blocks_ok,int *lut_blocks_fehler)
{
   char *lut_filename_p,*lut_blocks_ok_p,*lut_blocks_fehler_p;
   int retval,rv;

   retval=lut_blocks(mode,&lut_filename_p,&lut_blocks_ok_p,&lut_blocks_fehler_p);

      /* alle drei retvals in einem if() in Handles umwandeln; es kÃ¶nnen nur
       * malloc Fehler vorkommen, dann ist doch alles zu spÃ¤t... daher keine
       * weitere Unterscheidung hier.
       */
   if((rv=kc_ptr2id(lut_filename_p,lut_filename,1)<0) || (rv=kc_ptr2id(lut_blocks_ok_p,lut_blocks_ok,1)<0)
         || (rv=kc_ptr2id(lut_blocks_fehler_p,lut_blocks_fehler,1)<0)){
      FREE(lut_filename_p);
      FREE(lut_blocks_ok_p);
      FREE(lut_blocks_fehler_p);
      return rv;
   }
   return retval;
}

/* Funktion current_lutfile_name() +§§§1 */
/* ###########################################################################
 * # current_lutfile_name(): Name, benutztes Set und Init-Level der aktuellen#
 * # LUT-Datei holen. Die Funktion wird intern zum Nachladen der Indexblocks #
 * # benutzt, ist aber auch als Info interessant, falls für die LUT-Datei    # 
 * # die Default-Werte benutzt wurden (Pfad und Dateiname).                  #
 * #                                                                         #
 * # Copyright (C) 2011 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *current_lutfile_name(int *set,int *level,int *retval)
{
   if(init_status<7 || !current_lutfile){
      if(retval)*retval=LUT2_NOT_INITIALIZED;
      if(set)*set=0;
      if(level)*level=-1;
      return NULL;
   }
   if(set)*set=current_lut_set;
   if(level)*level=current_lut_level;
   if(retval)*retval=OK;
   return current_lutfile;
}

/* Funktion lut_index() +§§§1 */
/* ###########################################################################
 * # lut_index(): Index einer BLZ in den internen Arrays bestimmen           #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int lut_index(char *b)
{
   short *iptr;
   int n,h;

   if((init_status&7)!=7)RETURN(LUT2_NOT_INITIALIZED);   /* BLZ oder atoi_table noch nicht initialisiert */
   while(*b==' ' || *b=='\t')b++;   /* führende Blanks/Tabs entfernen */
   n= b8[UI *b]; h= h1[UI *b++];
   n+=b7[UI *b]; h+=h2[UI *b++];
   n+=b6[UI *b]; h+=h3[UI *b++];
   n+=b5[UI *b]; h+=h4[UI *b++];
   n+=b4[UI *b]; h+=h5[UI *b++];
   n+=b3[UI *b]; h+=h6[UI *b++];
   n+=b2[UI *b]; h+=h7[UI *b++];
   n+=b1[UI *b]; h+=h8[UI *b++];
   n+=b0[UI *b];     /* abfangen, wenn eine BLZ mehr als 8 Ziffern hat ist */

   if(n>=BLZ_FEHLER)RETURN(INVALID_BLZ_LENGTH);  /* nicht im BLZ-Array enthalten */
   if(blz[hash[h]]==n)return hash[h];           /* BLZ gefunden, Index zurückgeben */
   iptr=hash+h+1;

      /* die BLZs sind nach Größe sortiert, unbelegte Felder zeigen auf
       * blz[lut2_cnt_hs]. Dieser Wert ist mit MAX_INT belegt. Falls also die
       * BLZ, die einem Hashwert zugeordnet wird, größer als n ist, gibt es die
       * gesuchte Zahl im BLZ-Array nicht.
       */
   if(blz[*iptr]>n)RETURN(INVALID_BLZ);
   if(blz[*iptr]==n)return *iptr;
   if(blz[*++iptr]>n)RETURN(INVALID_BLZ);
   if(blz[*iptr]==n)return *iptr;

      /* bis hierhin dürften die meisten BLZs gefunden sein, der Rest in einer Schleife */
   while(1){
      if(blz[*++iptr]>n)RETURN(INVALID_BLZ);
      if(blz[*iptr]==n)return *iptr;
   }
}

/* Funktion lut_index_i() +§§§1 */
/* ###########################################################################
 * # lut_index_i(): Index einer BLZ in den internen Arrays bestimmen         #
 * #                (die BLZ liegt als Integerwert vor).                     #
 * #                Diese Funktion ist nicht so optimiert wie lut_index(),   #
 * #                da sie nicht in zeitkritischen Routinen benutzt wird.    #
 * #                                                                         #
 * # Copyright (C) 2009 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int lut_index_i(int b)
{
   short *iptr;
   int n,br,h;

   if((init_status&7)!=7)RETURN(LUT2_NOT_INITIALIZED);   /* BLZ oder atoi_table noch nicht initialisiert */
   if(b<10000000 || b>99999999)RETURN(INVALID_BLZ_LENGTH);  /* ungültig */
   n=b;
   br=b%10; b/=10; h= h8[br+'0'];
   br=b%10; b/=10; h+=h7[br+'0'];
   br=b%10; b/=10; h+=h6[br+'0'];
   br=b%10; b/=10; h+=h5[br+'0'];
   br=b%10; b/=10; h+=h4[br+'0'];
   br=b%10; b/=10; h+=h3[br+'0'];
   br=b%10; b/=10; h+=h2[br+'0'];
   br=b%10;        h+=h1[br+'0'];

   if(blz[hash[h]]==n)return hash[h];           /* BLZ gefunden, Index zurückgeben */
   iptr=hash+h+1;

      /* die BLZs sind nach Größe sortiert, unbelegte Felder zeigen auf
       * blz[lut2_cnt_hs]. Dieser Wert ist mit MAX_INT belegt. Falls also die
       * BLZ, die einem Hashwert zugeordnet wird, größer als n ist, gibt es die
       * gesuchte Zahl im BLZ-Array nicht.
       */
   if(blz[*iptr]>n)RETURN(INVALID_BLZ);
   if(blz[*iptr]==n)return *iptr;
   if(blz[*++iptr]>n)RETURN(INVALID_BLZ);
   if(blz[*iptr]==n)return *iptr;

      /* bis hierhin dürften die meisten BLZs gefunden sein, der Rest in einer Schleife */
   while(1){
      if(blz[*++iptr]>n)RETURN(INVALID_BLZ);
      if(blz[*iptr]==n)return *iptr;
   }
}

/* Funktionen, um einzelne Felder der LUT-Datei zu extrahieren +§§§1 */
/* ###########################################################################
 * # Die folgenden Funktionen extrahieren einzelne Felder aus der LUT-Datei  #
 * # und geben sie als String oder Zahl (je nach Typ) direkt zurück. Für den #
 * # Rückgabewert kann ein Integerpointer übergeben werden; falls diese      #
 * # Variable gesetzt ist, wird der Rückgabewert in die Variable geschrieben,#
 * # falls für die Variable NULL übergeben wird, wird er ignoriert.          #
 * # Die Funktionen enthalten noch einen Paramer zweigstelle, mit dem die    #
 * # Daten der Filialen bestimmt werden. Die Hauptstelle erhält man immer    #
 * # mit zweigstelle 0; falls der Index einer Filiale zu groß ist, wird ein  #
 * # Leerstring bzw. 0 zurückgegeben und retval auf den Wert                 #
 * # LUT2_INDEX_OUT_OF_RANGE gesetzt. Die Anzahl der Filialen läßt sich mit  #
 * # der Funktion lut_filialen() ermitteln.                                  #
 * #                                                                         #
 * # Parameter der folgenden Funktionen:                                     #
 * #                                                                         #
 * # b:            Bankleitzahl                                              #
 * #               Die alten Routinen erhalten die BLZ als char * Pointer;   #
 * #               es gibt noch einen Satz neuer Funktionen (mit dem Suffix  #
 * #               _i), bei denen die BLZ ein Integerwert ist (das wurde     #
 * #               für die Suchroutinen benötigt)                            #
 * #                                                                         #
 * # zweigstelle:  Index der Nebenstelle; 0 für Hauptstelle                  #
 * #                                                                         #
 * # retval:       Pointervariable, in die der Rückgabewert geschrieben      #
 * #               wird. Falls für retval NULL übergeben wird, wird der      #
 * #               Rückgabewert verworfen.                                   #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

/* Funktion lut_blz() +§§§2 */
/* ###########################################################################
 * # lut_blz(): Test ob eine BLZ existiert                                   #
 * #                                                                         #
 * # Diese Funktion testet, ob eine BLZ (und Zweigstelle, falls gewünscht)   #
 * # existiert und gültig ist.                                               #
 * #                                                                         #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_blz(char *b,int zweigstelle)
{
   int idx;

   if(!blz)RETURN(LUT2_BLZ_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)return idx;
   if(zweigstelle<0 || (filialen && zweigstelle>=filialen[idx]) || (zweigstelle && !filialen))
      RETURN(LUT2_INDEX_OUT_OF_RANGE);
   return OK;
}

DLL_EXPORT int lut_blz_i(int b,int zweigstelle)
{
   int idx;

   if(!blz)RETURN(LUT2_BLZ_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)return idx;
   if(zweigstelle<0 || (filialen && zweigstelle>=filialen[idx]) || (zweigstelle && !filialen))
      RETURN(LUT2_INDEX_OUT_OF_RANGE);
   return OK;
}

/* Funktion lut_filialen() +§§§2 */
/* ###########################################################################
 * # lut_filialen(): Anzahl der Filialen zu einer gegebenen Bankleitzahl     #
 * # bestimmen.                                                              #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_filialen(char *b,int *retval)
{
   int idx;

   if(!filialen)INVALID_I(LUT2_FILIALEN_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_I(idx);
   if(retval)*retval=OK;
   return filialen[idx];
}

DLL_EXPORT int lut_filialen_i(int b,int *retval)
{
   int idx;

   if(!filialen)INVALID_I(LUT2_FILIALEN_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   if(retval)*retval=OK;
   return filialen[idx];
}

/* Funktion lut_name() +§§§2 */
/* ###########################################################################
 * # lut_name(): Banknamen (lange Form) bestimmen                            #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *lut_name(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!name)INVALID_C(LUT2_NAME_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;
   return name[startidx[idx]+zweigstelle];
}

DLL_EXPORT const char *lut_name_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!name)INVALID_C(LUT2_NAME_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;
   return name[startidx[idx]+zweigstelle];
}

/* Funktion lut_name_kurz() +§§§2 */
/* ###########################################################################
 * # lut_name_kurz(): Kurzbezeichnung mit Ort einer Bank bestimmen           #
 * #                                                                         #
 * # Kurzbezeichnung und Ort sollen für die Empfängerangaben auf Rechnungen  #
 * # und Formularen angegeben werden. Hierdurch wird eine eindeutige Zu-     #
 * # ordnung der eingereichten Zahlungsaufträge ermöglicht. Auf Grund der    #
 * # Regelungen in den Richtlinien beziehungsweise Zahlungsverkehrs-Abkommen #
 * # der deutschen Kreditwirtschaft ist die Länge der Angaben für die        #
 * # Bezeichnung des Kreditinstituts begrenzt.                               #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *lut_name_kurz(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!name_kurz)INVALID_C(LUT2_NAME_KURZ_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;
   return name_kurz[startidx[idx]+zweigstelle];
}

DLL_EXPORT const char *lut_name_kurz_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!name_kurz)INVALID_C(LUT2_NAME_KURZ_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;
   return name_kurz[startidx[idx]+zweigstelle];
}

/* Funktion lut_plz() +§§§2 */
/* ###########################################################################
 * # lut_plz(): Postleitzahl bestimmen                                       #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_plz(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!plz)INVALID_I(LUT2_PLZ_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return plz[startidx[idx]+zweigstelle];
}

DLL_EXPORT int lut_plz_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!plz)INVALID_I(LUT2_PLZ_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return plz[startidx[idx]+zweigstelle];
}

/* Funktion lut_ort() +§§§2 */
/* ###########################################################################
 * # lut_ort(): Sitz einer Bank bestimmen                                    #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *lut_ort(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!ort)INVALID_C(LUT2_ORT_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;
   return ort[startidx[idx]+zweigstelle];
}

DLL_EXPORT const char *lut_ort_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!ort)INVALID_C(LUT2_ORT_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;
   return ort[startidx[idx]+zweigstelle];
}

/* Funktion lut_pan() +§§§2 */
/* ###########################################################################
 * # lut_pan(): PAN-Nummer bestimmen                                         #
 * #                                                                         #
 * # Für den internationalen Kartenzahlungsverkehr mittels Bankkunden-       #
 * # karten haben die Spitzenverbände des Kreditgewerbes und die Deutsche    #
 * # Bundesbank eine gesonderte Institutsnummerierung festgelegt; danach     #
 * # erhält das kartenausgebende Kreditinstitut eine fünfstellige Instituts- #
 * # nummer für PAN (= Primary Account Number). Diese setzt sich zusammen    #
 * # aus der Institutsgruppennummer (grundsätzlich = vierte Stelle der       #
 * # Bankleitzahl) und einer nachfolgenden vierstelligen, von den einzelnen  #
 * # Institutionen frei gewählten Nummer. Abweichend hiervon ist den         #
 * # Mitgliedsinstituten des Bundesverbandes deutscher Banken e.V. sowie     #
 * # den Stellen der Deutschen Bundesbank stets die Institutsgruppennummer   #
 * # 2 zugewiesen worden.                                                    #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_pan(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!pan)INVALID_I(LUT2_PAN_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return pan[startidx[idx]+zweigstelle];
}

DLL_EXPORT int lut_pan_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!pan)INVALID_I(LUT2_PAN_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return pan[startidx[idx]+zweigstelle];
}

/* Funktion lut_bic() und lut_bic_int() +§§§2 */
/* ###########################################################################
 * # lut_bic(): BIC (Bank Identifier Code) einer Bank bestimmen.             #
 * #                                                                         #
 * # Der Bank Identifier Code (BIC) besteht aus acht oder elf                #
 * # zusammenhängenden Stellen und setzt sich aus den Komponenten BANKCODE   #
 * # (4 Stellen), LÄNDERCODE (2 Stellen), ORTSCODE (2 Stellen) sowie ggf.    #
 * # einem FILIALCODE (3 Stellen) zusammen.                                  #
 * #                                                                         #
 * # Jedes Kreditinstitut führt grundsätzlich einen BIC je Bankleitzahl und  #
 * # teilt diesen der Deutschen Bundesbank mit. Ausnahmen hiervon können auf #
 * # Antrag für Bankleitzahlen zugelassen werden, die im BIC-gestützten      #
 * # Zahlungsverkehr (grenzüberschreitender Zahlungsverkehr und inländischer #
 * # Individualzahlungsverkehr) nicht verwendet werden.                      #
 * #                                                                         #
 * # Falls für eine Bank ein Nachfolge-Institut eingetragen ist, wird nach   #
 * # den Vorschriften der Bundesbank der BIC des Nachfolgeinstituts ausge-   #
 * # geben. Falls der BLZ ein ! vorausgestellt wird, wird der BIC aus der    #
 * # BLZ-Datei benutzt.                                                      #
 * #                                                                         #
 * # Der Parameter zweigstelle wird ignoriert; für den BIC ist grundsätzlich #
 * # derjenige der Hauptstelle zu nehmen (Bundesbank-Vorschrift). Der        #
 * # Parameter wird nur aus Kompatibilitätsgründen weiter mitgeführt.        #
 * #                                                                         #
 * # Die Funktion wird auch in iban_regel_cvt() benutzt; um einen rekursiven #
 * # Aufruf zu vermeiden, wurde die alte Version umbenannt in lut_bic_int()  #
 * # (ohne IBAN-Regeln) sowie eine neue Funktion, die die IBAN Regeln        #
 * # auswertet. Falls der BIC durch eine Regel geändert wird, wird als       #
 * # Rückgabewert statt OK der Wert OK_INVALID_FOR_IBAN zurückgegeben. Der   #
 * # korrekte Wert läßt sich in diesem Fall durch die Funktion iban_bic_gen()#
 * # ermitteln.                                                              #
 * #                                                                         #
 * # Copyright (C) 2007,2013 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

DLL_EXPORT const char *lut_bic(char *b,int zweigstelle,int *retval)
{
#if USE_IBAN_RULES
   char blz2[12],kto2[12];
   const char *bic,*bic_neu;
   int ret,regel;

   if((ret=iban_init())<OK){  /* alle notwendigen Blocks kontrollieren, evl. nachladen */
      if(retval)*retval=ret;
      return NULL;
   }
   bic=lut_bic_int(b,zweigstelle,retval); /* BIC aus der LUT-Datei holen */
   regel=lut_iban_regel(b,0,&ret);
   if(retval && ret==OK){  /* Test nur notwendig, falls retval nicht NULL */
      if(regel>=31 && regel<=35)
         *retval=OK_HYPO_REQUIRES_KTO;  /* Sonderfall ehemalige Hypobank */
      else{
         strcpy(blz2,b);
         strcpy(kto2,"13");   /* nur Dummy für Funktionsaufruf */
         iban_regel_cvt(blz2,kto2,&bic_neu,regel,NULL); /* Rückgabewert egal, nur bic_neu interessiert */
         if(bic && bic_neu && strcasecmp(bic,bic_neu))*retval=OK_INVALID_FOR_IBAN;  /* BIC wurde durch eine Regel geändert */
      }
   }
      /* Rückgabe ist immer der BIC aus der LUT-Datei, nicht der durch Regeln modifizierte Wert.
       * Falls der BIC durch die Regel modifiziert wird, wird das nur durch retval angezeigt.
       */
   return bic;
#else
   return lut_bic_int(b,zweigstelle,retval);
#endif
}

static const char *lut_bic_int(char *b,int zweigstelle,int *retval)
{
   int idx,force_old,blz_i;

   if(!bic)INVALID_C(LUT2_BIC_NOT_INITIALIZED);
   if(*b=='!'){
      b++;
      force_old=1;
   }
   if((idx=lut_index(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;

      /* falls eine Nachfolge-BLZ eingetragen ist, wird diese benutzt */
   if(!nachfolge_blz && !force_old)INVALID_C(LUT2_NACHFOLGE_BLZ_NOT_INITIALIZED);
   if((blz_i=lut_nachfolge_blz(b,0,NULL))){
      if((idx=lut_index_i(blz_i))<0)INVALID_C(idx);
      if(retval)*retval=OK_NACHFOLGE_BLZ_USED;
   }
   else
      if(retval)*retval=OK;
   return bic[startidx[idx]+zweigstelle];
}

   /* Die Funktion lut_bic_h() entspricht der Funktion lut_bic(), nur wird
    * anstelle des individuellen BICs der BIC der Hauptstelle zurückgeliefert.
    * Die Funktion steht in Zusammenhang mit der Funktionsgruppe bic_name(),
    * bic_kurzname(), bic_ort()... die ebenfalls den BIC der Hauptstelle benutzen.
    */
DLL_EXPORT const char *lut_bic_h(char *b,int zweigstelle,int *retval)
{
   int idx,force_old,blz_i;

   if(!bic_h)INVALID_C(LUT2_BIC_NOT_INITIALIZED);
   if(*b=='!'){
      b++;
      force_old=1;
   }
   if((idx=lut_index(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;

      /* falls eine Nachfolge-BLZ eingetragen ist, wird diese benutzt */
   if(!nachfolge_blz && !force_old)INVALID_C(LUT2_NACHFOLGE_BLZ_NOT_INITIALIZED);
   if((blz_i=lut_nachfolge_blz(b,0,NULL))){
      if((idx=lut_index_i(blz_i))<0)INVALID_C(idx);
      if(retval)*retval=OK_NACHFOLGE_BLZ_USED;
   }
   else
      if(retval)*retval=OK;
   return bic_h[startidx[idx]+zweigstelle];
}

   /* Die Funktion lut_bic_i() (mit Integer-Wert für die BLZ) bietet bei Verwendung der
    * IBAN-Regeln keinen Vorteil mehr. Daher wird die BLZ in einen String umgewandelt
    * und dann die Funktion lut_bic() aufgerufen. Die Funktion lut_bic_hi() entspricht
    * lut_bic_h().
    */
DLL_EXPORT const char *lut_bic_i(int b,int zweigstelle,int *retval)
{
#if !USE_IBAN_RULES
   int idx;

   if(!bic)INVALID_C(LUT2_BIC_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;
   return bic[startidx[idx]+zweigstelle];
#else
   char b_a[9];

   snprintf(b_a,9,"%08d",b);
   return lut_bic(b_a,zweigstelle,retval);
#endif
}

DLL_EXPORT const char *lut_bic_hi(int b,int zweigstelle,int *retval)
{
#if !USE_IBAN_RULES
   int idx;

   if(!bic_h)INVALID_C(LUT2_BIC_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_C(idx);
   CHECK_OFFSET_S;
   return bic_h[startidx[idx]+zweigstelle];
#else
   char b_a[9];

   snprintf(b_a,9,"%08d",b);
   return lut_bic_h(b_a,zweigstelle,retval);
#endif
}

/* Funktion lut_nr() +§§§2 */
/* ###########################################################################
 * # lut_nr(): Nummer des Datensatzes in der BLZ-Datei                       #
 * #                                                                         #
 * # Bei jeder Neuanlage eines Datensatzes wird von der Deutschen Bundesbank #
 * # automatisiert eine eindeutige Nummer vergeben. Eine einmal verwendete   #
 * # Nummer wird nicht noch einmal vergeben.                                 #
 * #                                                                         #
 * # Copyright (C) 2009 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_nr(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!bank_nr)INVALID_I(LUT2_NR_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return bank_nr[startidx[idx]+zweigstelle];
}

DLL_EXPORT int lut_nr_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!bank_nr)INVALID_I(LUT2_NR_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return bank_nr[startidx[idx]+zweigstelle];
}

/* Funktion lut_pz() +§§§2 */
/* ###########################################################################
 * # lut_pz(): Prüfzifferverfahren für eine Bankleitzahl. Das Verfahren wird #
 * # numerisch zurückgegeben, also z.B. 108 für die Methode A8.              #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_pz(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!pz_methoden)INVALID_I(LUT2_PZ_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return pz_methoden[idx];
}

DLL_EXPORT int lut_pz_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!pz_methoden)INVALID_I(LUT2_PZ_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return pz_methoden[idx];
}

/* Funktion lut_aenderung() +§§§2 */
/* ###########################################################################
 * # lut_aenderung(): Änderungskennzeichen einer Bank betimmen (A Addition,  #
 * # M Modified, U Unchanged, D Deletion). Gelöschte Datensätze werden mit   #
 * # dem Kennzeichen 'D' gekennzeichnet und sind - als Hinweis - letztmalig  #
 * # in der Bankleitzahlendatei enthalten. Diese Datensätze sind ab dem      #
 * # Gültigkeitstermin der Bankleitzahlendatei im Zahlungsverkehr nicht mehr #
 * # zu verwenden.                                                           #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_aenderung(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!aenderung)INVALID_I(LUT2_AENDERUNG_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return aenderung[startidx[idx]+zweigstelle];
}

DLL_EXPORT int lut_aenderung_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!aenderung)INVALID_I(LUT2_AENDERUNG_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return aenderung[startidx[idx]+zweigstelle];
}

/* Funktion lut_loeschung() +§§§2 */
/* ###########################################################################
 * # lut_loeschung(): Hinweis auf eine beabsichtigte Bankleitzahllöschung    #
 * #                                                                         #
 * # Zur frühzeitigen Information der Teilnehmer am Zahlungsverkehr und      #
 * # zur Beschleunigung der Umstellung der Bankverbindung kann ein Kredit-   #
 * # institut, das die Löschung einer Bankleitzahl mit dem Merkmal 1 im      #
 * # Feld 2 (Hauptstelle) beabsichtigt, die Löschung ankündigen. Die         #
 * # Ankündigung kann erfolgen, sobald das Kreditinstitut seine Kunden       #
 * # über die geänderte Kontoverbindung informiert hat. Es wird empfohlen,   #
 * # diese Ankündigung mindestens eine Änderungsperiode vor der              #
 * # eigentlichen Löschung anzuzeigen.                                       #
 * #                                                                         #
 * # Das Feld enthält das Merkmal 0 (keine Angabe) oder 1 (BLZ im Feld 1     #
 * # ist zur Löschung vorgesehen). Die Rückgabe erfolgt als ASCII '0' '1'.   #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_loeschung(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!loeschung)INVALID_I(LUT2_LOESCHUNG_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return loeschung[startidx[idx]+zweigstelle];
}

DLL_EXPORT int lut_loeschung_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!loeschung)INVALID_I(LUT2_LOESCHUNG_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return loeschung[startidx[idx]+zweigstelle];
}

/* Funktion lut_nachfolge_blz() +§§§2 */
/* ###########################################################################
 * # lut_nachfolge_blz(): entweder 0 (Bankleitzahl ist nicht zur Löschung    #
 * # vorgesehen, bzw. das Institut hat keine Nachfolge-BLZ veröffentlicht)   #
 * # oder eine Bankleitzahl. Eine Bankleitzahl kann nur für Hauptstellen an- #
 * # gegeben werden werden, wenn die Bankleitzahl zur Löschung angekündigt   #
 * # wurde (lut_loeschung()==1) oder die Bankleitzahl zum aktuellen Gültig-  #
 * # keitstermin gelöscht wird (lut_aenderung()=='D').                       #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_nachfolge_blz(char *b,int zweigstelle,int *retval)
{
   int idx;

   if(!nachfolge_blz)INVALID_I(LUT2_NACHFOLGE_BLZ_NOT_INITIALIZED);
   if((idx=lut_index(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return nachfolge_blz[startidx[idx]+zweigstelle];
}

DLL_EXPORT int lut_nachfolge_blz_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!nachfolge_blz)INVALID_I(LUT2_NACHFOLGE_BLZ_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return nachfolge_blz[startidx[idx]+zweigstelle];
}

/* Funktion lut_iban_regel() +§§§2 */
/* ###########################################################################
 * # lut_iban_regel(): IBAN-Regel zu einer BLZ                               #
 * #                                                                         #
 * # Ab Juni 2013 wird in der Bankleitzahlendatei der Deutschen Bundesbank   #
 * # ein neues Feld eingeführt, das die Regel angibt, mit der die IBANs der  #
 * # Bank aus BLZ und Kontonummer bestimmt werden. Eine IBAN-Regel besteht   #
 * # aus einer vierstelligen Nummer und einer zweistelligen Versionszahl;    #
 * # sie wird in konto_check als eine sechsstellige Nummer dargestellt.      #
 * #                                                                         #
 * # Copyright (C) 2013 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_iban_regel(char *b,int zweigstelle,int *retval)
{
   int idx,ret;

   if((ret=iban_init())<OK)return ret;  /* alle notwendigen Blocks kontrollieren, evl. nachladen */
   if(!iban_regel){
      if(retval)*retval=LUT2_IBAN_REGEL_NOT_INITIALIZED;
      return 0;   /* falls der Block nicht eingelesen wurde, Standard-Regel verwenden */
   }
   while(*b=='@' || *b=='+')b++; /* Sonderzeichen in BLZ ignorieren */
   if((idx=lut_index(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return iban_regel[startidx[idx]+zweigstelle];
}

DLL_EXPORT int lut_iban_regel_i(int b,int zweigstelle,int *retval)
{
   int idx;

   if(!iban_regel)INVALID_I(LUT2_IBAN_REGEL_NOT_INITIALIZED);
   if((idx=lut_index_i(b))<0)INVALID_I(idx);
   CHECK_OFFSET_I;
   return iban_regel[startidx[idx]+zweigstelle];
}

/* Funktion iban_init() +§§§2 */
/* ###########################################################################
 * # iban_init(): Diese Funktion testet, ob alle LUT-Blocks die zur IBAN-    #
 * # Berechnung notwendig sind, schon geladen wurden; falls nicht, werden    #
 * # die fehlenden Daten (per inkrementeller Initialisierung) nachgeladen.   #
 * #                                                                         #
 * # Copyright (C) 2013 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int iban_init(void)
{

      /* Fehlerstatus von früherem Test */
   if(extra_init_done<0)
      return LUT2_NOT_ALL_IBAN_BLOCKS_LOADED;
   else if(extra_init_done>0)
      return OK;

      /* die Funktion wurde noch nicht aufgerufen; jetzt die notwendige Blocks
       * testen (durch die entsprechenden Variablen)
      */
   if(!extra_init_done && (!loeschung || !aenderung || !iban_regel || !bic || !nachfolge_blz)){
      extra_init_done=1;   /* Flag setzen daß schon nachinitialisiert wurde */
      if((kto_check_init(current_lutfile,lut_set_iban,NULL,0,1)<0)
            && (!loeschung || !aenderung || !iban_regel || !bic || !nachfolge_blz)){
         extra_init_done=-1;
         return LUT2_NOT_ALL_IBAN_BLOCKS_LOADED;
      }
   }
   return OK;
}

/* Funktion iban_regel_cvt() +§§§2 */
/* ###########################################################################
 * # iban_regel_cvt(): IBAN-Regel auf BLZ/Kto-Kombination anwenden.          #
 * #                                                                         #
 * # Diese Funktion bestimmt zu einer BLZ die zugehörige IBAN-Regel und      #
 * # wendet diese dann auf die angegebene Bankverbindung an. Bei manchen     #
 * # IBAN-Regeln werden BLZ und/oder Konto durch andere Werte ersetzt; daher #
 * # ist es wichtig, daß beide Werte in lokalen Arrays der aufrufenden       #
 * # Funktion gespeichert sind und somit überschrieben werden können.        #
 * #                                                                         #
 * # Der Rückgabewert gibt nähere Aufschlüsse über die Anwendung der Regeln  #
 * # und ob eine IBAN berechnet werden darf.                                 #
 * #                                                                         #
 * # Copyright (C) 2013 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

#if USE_IBAN_RULES
static int iban_regel_cvt(char *blz,char *kto,const char **bicp,int regel_version,RETVAL *retvals)
{
   char tmp_buffer[16];
   int regel,version,b,b_alt,b_neu,k1,k2,k3,not_ok,i,ret,loesch,idx,pz_methode,uk_cnt,tmp;

      /* prüfen, ob bereits initialisiert wurde */
   INITIALIZE_WAIT;
   if((init_status&7)!=7)RETURN(LUT2_NOT_INITIALIZED);   /* Initialisierung ist notwendig für etliche Sachen */
   for(not_ok=i=0;i<8;i++)not_ok|=is_not_digit[I blz[i]];
   if(not_ok)return INVALID_BLZ;
   for(i=0;i<10 && kto[i];i++)not_ok|=is_not_digit[I kto[i]];
   if(not_ok)return INVALID_KTO;

   if((ret=iban_init())<OK)return ret;  /* alle notwendigen Blocks kontrollieren, evl. nachladen */
   regel=regel_version/100;
   version=regel_version%100;
   *bicp=NULL;
   ret=OK;

      /* zunächst einige Sonderfälle (weggelassene Unterkonten) für Regel 0 behandeln;
       * diese sind auch wichtig, falls die IBAN-Regeln nicht in der LUT-Datei enthalten sind.
       * Die Rückgabe differenziert allerdings nicht mehr nach der Art der Unterkonten; diese
       * werden nur stillschweigend eingefügt (wie im "SEPA Account Converter").
       */
   if(regel==0){  /* in den anderen Regeln wird die Verschiebung bei Bedarf ebenfalls gemacht */
      if(((ret=kto_check_blz_x(blz,kto,&uk_cnt))<=0))return ret;  /* Fehler bei Regel 0: zurückgeben, keine Berechnung */
      switch(uk_cnt){
         case 1:
            ret=OK_UNTERKONTO_ATTACHED;
            kto[0]=kto[1];
            kto[1]=kto[2];
            kto[2]=kto[3];
            kto[3]=kto[4];
            kto[4]=kto[5];
            kto[5]=kto[6];
            kto[6]=kto[7];
            kto[7]=kto[8];
            kto[8]=kto[9];
            kto[9]='0';
            break;
         case 2:
            ret=OK_UNTERKONTO_ATTACHED;
            kto[0]=kto[2];
            kto[1]=kto[3];
            kto[2]=kto[4];
            kto[3]=kto[5];
            kto[4]=kto[6];
            kto[5]=kto[7];
            kto[6]=kto[8];
            kto[7]=kto[9];
            kto[8]=kto[9]='0';
            break;
         case 3:
            ret=OK_UNTERKONTO_ATTACHED;
            kto[0]=kto[3];
            kto[1]=kto[4];
            kto[2]=kto[5];
            kto[3]=kto[6];
            kto[4]=kto[7];
            kto[5]=kto[8];
            kto[6]=kto[9];
            kto[7]=kto[8]=kto[9]='0';
            break;
         default:
            break;
      }
   }


      /* erstmal Konto und BLZ nach Integer umwandeln */
   k1=b2[I kto[0]]+b1[I kto[1]];
   k2=b8[I kto[2]]+b7[I kto[3]]+b6[I kto[4]]+b5[I kto[5]]+b4[I kto[6]]+b3[I kto[7]]+b2[I kto[8]]+b1[I kto[9]];
   b_alt=b=b8[I blz[0]]+b7[I blz[1]]+b6[I blz[2]]+b5[I blz[3]]+b4[I blz[4]]+b3[I blz[5]]+b2[I blz[6]]+b1[I blz[7]];

      /* Löschkennzeichen der BLZ überprüfen, u.U. Nachfolge-BLZ einsetzen */
   if(lut_aenderung_i(b,0,NULL)=='D' && !(b=lut_nachfolge_blz_i(b,0,NULL)))return BLZ_MARKED_AS_DELETED;

#define RETURN_OK do{if(b!=b_alt)return OK_BLZ_REPLACED; else return OK;}while(0) /* Löschkennzeichen und Nachfolge-BLZ beachten für retval */
#define RETURN_OK_KTO_REPLACED do{if(b!=b_alt)return OK_BLZ_KTO_REPLACED; else return OK_KTO_REPLACED;}while(0) /* Löschkennzeichen und Nachfolge-BLZ beachten für retval */

      /* Im Folgenden werden die IBAN-Regeln auf die übergebene BLZ und
       * Kontonummer angewendet.
       */
   switch(regel){

      /* Standardregel zur IBAN-Berechnung: Default, falls nichts anderes angegeben */
      case 0:
         if(ret==OK_UNTERKONTO_ATTACHED)return ret;
         RETURN_OK;


         /* Standardregel: keine Berechnung */
      case 1: 
         return NO_IBAN_CALCULATION;


         /* Augsburger Aktienbank */
      case 2:

         /* Konten ohne IBAN-Berechnung */
         if((kto[7]=='8' && kto[8]=='6') || kto[7]=='6')return NO_IBAN_CALCULATION;
         RETURN_OK;


         /* Aareal Bank AG */
      case 3:

         /* Konten ohne IBAN-Berechnung */
         if(!strcmp(kto,"6161604670"))return NO_IBAN_CALCULATION;
         RETURN_OK;


         /* Landesbank Berlin / Berliner Sparkasse */
      case 4:

         /* Umwandlung von Spendenkontonummern: */
         if(!k1)switch(k2){
            case 135:       strcpy(kto,"0990021440"); RETURN_OK_KTO_REPLACED;
            case 1111:      strcpy(kto,"6600012020"); RETURN_OK_KTO_REPLACED;
            case 1900:      strcpy(kto,"0920019005"); RETURN_OK_KTO_REPLACED;
            case 7878:      strcpy(kto,"0780008006"); RETURN_OK_KTO_REPLACED;
            case 8888:      strcpy(kto,"0250030942"); RETURN_OK_KTO_REPLACED;
            case 9595:      strcpy(kto,"1653524703"); RETURN_OK_KTO_REPLACED;
            case 97097:     strcpy(kto,"0013044150"); RETURN_OK_KTO_REPLACED;
            case 112233:    strcpy(kto,"0630025819"); RETURN_OK_KTO_REPLACED;
            case 336666:    strcpy(kto,"6604058903"); RETURN_OK_KTO_REPLACED;
            case 484848:    strcpy(kto,"0920018963"); RETURN_OK_KTO_REPLACED;
            default: RETURN_OK;
         }
         RETURN_OK;


         /* Commerzbank AG */
      case 5:  /* (ziemlig lang) */

            /* Prüfziffermethode holen */
         if((idx=lut_index(blz))<0)return idx;
         pz_methode=pz_methoden[idx];

            /* comdirect bank behält ihren BIC (Beispiel und Vergleich mit SEPA
             * Account Converter und VR Iban Konverter, sowie Anmerkung 6 in der
             * IBAN-Regel 5 auf S. 14); alle anderen BLZs der Commerzbank
             * bekommen COBADEFFXXX.
             */
         if(blz[3]=='4' && strcasecmp(lut_name(blz,0,NULL),"comdirect bank"))*bicp="COBADEFFXXX";

            /* BLZs ohne Prüfzifferberechnung */
         if(pz_methode==9)return OK_NO_CHK;

            /* Kontenkreis ohne IBAN-Berechnung (für etliche BLZs) */
         if(k1==9 && (k2>=98000000 && k2<=99499999))switch(b){
            case 10080900: return NO_IBAN_CALCULATION;
            case 12080000: return NO_IBAN_CALCULATION;
            case 13080000: return NO_IBAN_CALCULATION;
            case 14080000: return NO_IBAN_CALCULATION;
            case 15080000: return NO_IBAN_CALCULATION;
            case 16080000: return NO_IBAN_CALCULATION;
            case 17080000: return NO_IBAN_CALCULATION;
            case 18080000: return NO_IBAN_CALCULATION;
            case 20080055: return NO_IBAN_CALCULATION;
            case 20080057: return NO_IBAN_CALCULATION;
            case 21080050: return NO_IBAN_CALCULATION;
            case 21280002: return NO_IBAN_CALCULATION;
            case 21480003: return NO_IBAN_CALCULATION;
            case 21580000: return NO_IBAN_CALCULATION;
            case 22180000: return NO_IBAN_CALCULATION;
            case 22181400: return NO_IBAN_CALCULATION;
            case 22280000: return NO_IBAN_CALCULATION;
            case 24080000: return NO_IBAN_CALCULATION;
            case 24180001: return NO_IBAN_CALCULATION;
            case 25480021: return NO_IBAN_CALCULATION;
            case 25780022: return NO_IBAN_CALCULATION;
            case 25980027: return NO_IBAN_CALCULATION;
            case 26080024: return NO_IBAN_CALCULATION;
            case 26281420: return NO_IBAN_CALCULATION;
            case 26580070: return NO_IBAN_CALCULATION;
            case 26880063: return NO_IBAN_CALCULATION;
            case 26981062: return NO_IBAN_CALCULATION;
            case 28280012: return NO_IBAN_CALCULATION;
            case 29280011: return NO_IBAN_CALCULATION;
            case 30080055: return NO_IBAN_CALCULATION;
            case 30080057: return NO_IBAN_CALCULATION;
            case 31080015: return NO_IBAN_CALCULATION;
            case 32080010: return NO_IBAN_CALCULATION;
            case 33080030: return NO_IBAN_CALCULATION;
            case 34080031: return NO_IBAN_CALCULATION;
            case 34280032: return NO_IBAN_CALCULATION;
            case 36280071: return NO_IBAN_CALCULATION;
            case 36580072: return NO_IBAN_CALCULATION;
            case 40080040: return NO_IBAN_CALCULATION;
            case 41280043: return NO_IBAN_CALCULATION;
            case 42080082: return NO_IBAN_CALCULATION;
            case 42680081: return NO_IBAN_CALCULATION;
            case 43080083: return NO_IBAN_CALCULATION;
            case 44080055: return NO_IBAN_CALCULATION;
            case 44080057: return NO_IBAN_CALCULATION;
            case 44580070: return NO_IBAN_CALCULATION;
            case 45080060: return NO_IBAN_CALCULATION;
            case 46080010: return NO_IBAN_CALCULATION;
            case 47880031: return NO_IBAN_CALCULATION;
            case 49080025: return NO_IBAN_CALCULATION;
            case 50080055: return NO_IBAN_CALCULATION;
            case 50080057: return NO_IBAN_CALCULATION;
            case 50080081: if(version==0)return NO_IBAN_CALCULATION; else break; /* ab  Version 1 der Regel freigegeben */
            case 50080082: return NO_IBAN_CALCULATION;
            case 50680002: return NO_IBAN_CALCULATION;
            case 50780006: return NO_IBAN_CALCULATION;
            case 50880050: return NO_IBAN_CALCULATION;
            case 51080000: if(version==0)return NO_IBAN_CALCULATION; else break; /* ab  Version 1 der Regel freigegeben */
            case 51380040: return NO_IBAN_CALCULATION;
            case 52080080: return NO_IBAN_CALCULATION;
            case 53080030: return NO_IBAN_CALCULATION;
            case 54080021: return NO_IBAN_CALCULATION;
            case 54280023: return NO_IBAN_CALCULATION;
            case 54580020: return NO_IBAN_CALCULATION;
            case 54680022: return NO_IBAN_CALCULATION;
            case 55080065: return NO_IBAN_CALCULATION;
            case 57080070: return NO_IBAN_CALCULATION;
            case 58580074: return NO_IBAN_CALCULATION;
            case 59080090: return NO_IBAN_CALCULATION;
            case 60080055: return NO_IBAN_CALCULATION;
            case 60080057: return NO_IBAN_CALCULATION;
            case 60380002: return NO_IBAN_CALCULATION;
            case 60480008: return NO_IBAN_CALCULATION;
            case 61080006: return NO_IBAN_CALCULATION;
            case 61281007: return NO_IBAN_CALCULATION;
            case 61480001: return NO_IBAN_CALCULATION;
            case 62080012: return NO_IBAN_CALCULATION;
            case 62280012: return NO_IBAN_CALCULATION;
            case 63080015: return NO_IBAN_CALCULATION;
            case 64080014: return NO_IBAN_CALCULATION;
            case 64380011: return NO_IBAN_CALCULATION;
            case 65080009: return NO_IBAN_CALCULATION;
            case 65180005: return NO_IBAN_CALCULATION;
            case 65380003: return NO_IBAN_CALCULATION;
            case 66280053: return NO_IBAN_CALCULATION;
            case 66680013: return NO_IBAN_CALCULATION;
            case 67280051: return NO_IBAN_CALCULATION;
            case 69280035: return NO_IBAN_CALCULATION;
            case 70080056: return NO_IBAN_CALCULATION;
            case 70080057: return NO_IBAN_CALCULATION;
            case 70380006: return NO_IBAN_CALCULATION;
            case 71180005: return NO_IBAN_CALCULATION;
            case 72180002: return NO_IBAN_CALCULATION;
            case 73180011: return NO_IBAN_CALCULATION;
            case 73380004: return NO_IBAN_CALCULATION;
            case 73480013: return NO_IBAN_CALCULATION;
            case 74180009: return NO_IBAN_CALCULATION;
            case 74380007: return NO_IBAN_CALCULATION;
            case 75080003: return NO_IBAN_CALCULATION;
            case 76080053: return NO_IBAN_CALCULATION;
            case 79080052: return NO_IBAN_CALCULATION;
            case 79380051: return NO_IBAN_CALCULATION;
            case 79580099: return NO_IBAN_CALCULATION;
            case 80080000: return NO_IBAN_CALCULATION;
            case 81080000: return NO_IBAN_CALCULATION;
            case 82080000: return NO_IBAN_CALCULATION;
            case 83080000: return NO_IBAN_CALCULATION;
            case 84080000: return NO_IBAN_CALCULATION;
            case 85080200: return NO_IBAN_CALCULATION;
            case 86080055: return NO_IBAN_CALCULATION;
            case 86080057: return NO_IBAN_CALCULATION;
            case 87080000: return NO_IBAN_CALCULATION;
            default: break;
         }

         /* BLZ ohne IBAN-Berechnung
          * Eine Reihe Bankleitzahlen wurden ab Version 1 der Regel zur IBAN-Berechnung
          * freigegeben.
          */

         switch(b){
            case 10045050: if(version==0)return NO_IBAN_CALCULATION; else break;
            case 50040033: return NO_IBAN_CALCULATION;
            case 70045050: if(version==0)return NO_IBAN_CALCULATION; else break;
            case 10040085: if(version==0)return NO_IBAN_CALCULATION; else break;
            case 35040085: if(version==0)return NO_IBAN_CALCULATION; else break;
            case 36040085: if(version==0)return NO_IBAN_CALCULATION; else break;
            case 44040085: if(version==0)return NO_IBAN_CALCULATION; else break;
            case 50040085: if(version==0)return NO_IBAN_CALCULATION; else break;
            case 67040085: if(version==0)return NO_IBAN_CALCULATION; else break;
            case 82040085: if(version==0)return NO_IBAN_CALCULATION; else break;
            default: break;
         }

         /* Spendenkonten
          * einige Spendenkonten müssen auch noch Unterkonto 00   
          * angehängt bekommen, deshalb gibt es in diesem switch()
          * noch kein return :-(
          *
          * Seit Version 1.4 der Regel-Dokumentation der Commerzbank werden
          * Unterkonten in den Spendenkonten berücksichtigt, daher sind
          * return-Befehle (endlich) möglich.
          */                                                    
         switch(b){
            case 10040000: 
               if(!k1 && k2==7878){strcpy(kto,"0267878700"); RETURN_OK_KTO_REPLACED;}
               break;

            case 10080000:
               if(!k1)switch(k2){
                  case    1987: strcpy(kto,"0928127700"); RETURN_OK_KTO_REPLACED;
                  case    8888: strcpy(kto,"0928126501"); RETURN_OK_KTO_REPLACED;
                  case 1234567: strcpy(kto,"0920192001"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 12080000:
               if(!k1)switch(k2){
                  case   212121: strcpy(kto,"4050462200"); RETURN_OK_KTO_REPLACED;
                  case  7654321: strcpy(kto,"0144000700"); RETURN_OK_KTO_REPLACED;
                  case 12121212: strcpy(kto,"4101725100"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 16080000: 
               if(!k1){
                  if(k2== 123456){strcpy(kto,"0012345600"); RETURN_OK_KTO_REPLACED;}
                  if(k2==3030400){strcpy(kto,"4205227110"); RETURN_OK_KTO_REPLACED;}
               }
               break;

            case 20080000:
               if(!k1)switch(k2){
                  case   2222: strcpy(kto,"0903927200"); RETURN_OK_KTO_REPLACED;
                  case 505050: strcpy(kto,"0500100600"); RETURN_OK_KTO_REPLACED;
                  case 666666: strcpy(kto,"0900732500"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 25040066: 
               if(!k1 && k2==1919){strcpy(kto,"0141919100"); RETURN_OK_KTO_REPLACED;}
               break;

            case 26580070: 
               if(!k1 && k2==700){strcpy(kto,"0710000000"); RETURN_OK_KTO_REPLACED;}
               break;

            case 29080010: 
               if(!k1){
                  if(k2==  124124){strcpy(kto,"0107502000"); RETURN_OK_KTO_REPLACED;}
                  if(k2==12412400){strcpy(kto,"0107502000"); RETURN_OK_KTO_REPLACED;}
               }
               break;

            case 30040000: 
               if(!k1)switch(k2){
                  case  36: strcpy(kto,"0261103600");  RETURN_OK_KTO_REPLACED;
                  case 222: strcpy(kto,"0348010002"); RETURN_OK_KTO_REPLACED;
                  case 999: strcpy(kto,"0123799900"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 30080000: 
               if(!k1){
                  if(k2==  700000){strcpy(kto,"0800005000"); RETURN_OK_KTO_REPLACED;}
                  if(k2==70000000){strcpy(kto,"0800005000"); RETURN_OK_KTO_REPLACED;}
               }
               break;

            case 32040024: 
               if(!k1 && k2==47800){strcpy(kto,"0155515000"); RETURN_OK_KTO_REPLACED;}
               break;

            case 34280032: 
               if(!k1 && k2==14111935){strcpy(kto,"0645753800"); RETURN_OK_KTO_REPLACED;}
               break;

            case 36040039: 
               if(!k1 && k2==150){strcpy(kto,"0161620000"); RETURN_OK_KTO_REPLACED;}
               break;

            case 37040044:
               if(!k1)switch(k2){
                  case   1888: strcpy(kto,"0212129101"); RETURN_OK_KTO_REPLACED;
                  case 102030: strcpy(kto,"0222344400"); RETURN_OK_KTO_REPLACED;
                  case 300000: strcpy(kto,"0300000700"); RETURN_OK_KTO_REPLACED; 
               }
               break;

            case 37080040:
               if(!k1)switch(k2){
                  case     100: strcpy(kto,"0269100000"); RETURN_OK_KTO_REPLACED;
                  case     111: strcpy(kto,"0215022000"); RETURN_OK_KTO_REPLACED;
                  case    4004: strcpy(kto,"0233533500"); RETURN_OK_KTO_REPLACED;
                  case    4444: strcpy(kto,"0233000300"); RETURN_OK_KTO_REPLACED;
                  case   55555: strcpy(kto,"0263602501"); RETURN_OK_KTO_REPLACED;
                  case  182002: strcpy(kto,"0216603302"); RETURN_OK_KTO_REPLACED;
                  case  300000: strcpy(kto,"0983307900"); RETURN_OK_KTO_REPLACED;
                  case  333333: strcpy(kto,"0270330000"); RETURN_OK_KTO_REPLACED;
                  case  414141: strcpy(kto,"0041414100"); RETURN_OK_KTO_REPLACED;
                  case  555666: strcpy(kto,"0055566600"); RETURN_OK_KTO_REPLACED;
                  case  909090: strcpy(kto,"0269100000"); RETURN_OK_KTO_REPLACED;
                  case 5555500: strcpy(kto,"0263602501"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 38040007:
               if(!k1)switch(k2){
                  case      100: strcpy(kto,"0119160000"); RETURN_OK_KTO_REPLACED; /* steht so in der neuen Bundesbank-Datei, entspricht den neuen Richtlinien */
                  case      240: strcpy(kto,"0109024000"); RETURN_OK_KTO_REPLACED;
                  case     3366: strcpy(kto,"0385333000"); RETURN_OK_KTO_REPLACED;
                  case    55555: strcpy(kto,"0305555500"); RETURN_OK_KTO_REPLACED;
                  case   336666: strcpy(kto,"0105232300"); RETURN_OK_KTO_REPLACED;
                  case   414141: strcpy(kto,"0108000100"); RETURN_OK_KTO_REPLACED;
                  case   909090: strcpy(kto,"0119160000"); RETURN_OK_KTO_REPLACED; /* steht so in der neuen Bundesbank-Datei, entspricht den neuen Richtlinien */
                  case  1555555: strcpy(kto,"0258266600"); RETURN_OK_KTO_REPLACED;
                  case 43434343: strcpy(kto,"0118163500"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 39040013: 
               if(!k1 && k2==556){strcpy(kto,"0106555600"); RETURN_OK_KTO_REPLACED;}
               break;

            case 39080005: 
               if(!k1){
                  if(k2== 556){strcpy(kto,"0204655600"); RETURN_OK_KTO_REPLACED;}
                  if(k2==9800){strcpy(kto,"0208457000"); RETURN_OK_KTO_REPLACED;}
               }
               break;

            case 43080083: 
               if(!k1 && k2==4630){strcpy(kto,"0825110100"); RETURN_OK_KTO_REPLACED;}
               break;

            case 44040037: 
               if(k1==1 && k2==11111111){strcpy(kto,"0320565500"); RETURN_OK_KTO_REPLACED;}
               break;

            case 47840065:
               if(!k1)switch(k2){
                  case 50: strcpy(kto,"0150103000"); RETURN_OK_KTO_REPLACED;
                  case 55: strcpy(kto,"0150103000"); RETURN_OK_KTO_REPLACED;
                  case 99: strcpy(kto,"0150103000"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 47880031: 
               if(!k1 && k2==50){strcpy(kto,"0519899900"); RETURN_OK_KTO_REPLACED;}
               break;

            case 50040000: 
               if(!k1){
                  if(k2==  2000){strcpy(kto,"0728400300"); RETURN_OK_KTO_REPLACED;}
                  if(k2==101010){strcpy(kto,"0311011100"); RETURN_OK_KTO_REPLACED;}  
               }
               break;

            case 50080000:
               if(!k1)switch(k2){
                  case   6060: strcpy(kto,"0096736100"); RETURN_OK_KTO_REPLACED;
                  case   9000: strcpy(kto,"0026492100"); RETURN_OK_KTO_REPLACED;
                  case  42195: strcpy(kto,"0900333200"); RETURN_OK_KTO_REPLACED;
                  case 101010: strcpy(kto,"0090003500"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 50640015: 
               if(!k1 && k2==777){strcpy(kto,"0222222200"); RETURN_OK_KTO_REPLACED;}
               break;

            case 51080060: 
               if(!k1 && k2==123){strcpy(kto,"0012299300"); RETURN_OK_KTO_REPLACED;}
               break;

            case 55040022: 
               if(!k1){
                  if(k2==   555){strcpy(kto,"0211050000"); RETURN_OK_KTO_REPLACED;}
                  if(k2==343434){strcpy(kto,"0217900000"); RETURN_OK_KTO_REPLACED;}
               }
               break;

            case 57080070: 
               if(!k1 && k2==661){strcpy(kto,"0604101200"); RETURN_OK_KTO_REPLACED;}
               break;

            case 60040071: 
               if(k1==0 && k2==   502){strcpy(kto,"0525950200"); RETURN_OK_KTO_REPLACED;}
               if(k1==5 && k2==500500){strcpy(kto,"0512700600"); RETURN_OK_KTO_REPLACED;}  
               break;

            case 60080000: 
               if(k1==0 && k2==   502){strcpy(kto,"0901581400"); RETURN_OK_KTO_REPLACED;}
               if(k1==5 && k2==500500){strcpy(kto,"0901581400"); RETURN_OK_KTO_REPLACED;}
               break;

            case 61080006: 
               if(!k1 && k2==9999999){strcpy(kto,"0202427500"); RETURN_OK_KTO_REPLACED;}
               break;

            case 64140036: 
               if(!k1 && k2==8907339){strcpy(kto,"0890733900"); RETURN_OK_KTO_REPLACED;}
               break;

            case 66280053: 
               if(!k1 && k2==121212){strcpy(kto,"0625242400"); RETURN_OK_KTO_REPLACED;}
               break;

            case 68080030: 
               if(!k1 && k2==202){strcpy(kto,"0416520200"); RETURN_OK_KTO_REPLACED;}
               break;

            case 69240075: 
               if(!k1 && k2==444){strcpy(kto,"0445520000"); RETURN_OK_KTO_REPLACED;}
               break;

            case 70040041:
               if(k1==4 && k2==500500){strcpy(kto,"0400500500"); RETURN_OK_KTO_REPLACED;}  
               if(!k1)switch(k2){
                  case      94: strcpy(kto,"0212808000"); RETURN_OK_KTO_REPLACED;
                  case 1111111: strcpy(kto,"0152140000"); RETURN_OK_KTO_REPLACED;
                  case 7777777: strcpy(kto,"0213600000"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 70080000:
               if(!k1)switch(k2){
                  case       94: strcpy(kto,"0928553201"); RETURN_OK_KTO_REPLACED;
                  case   700000: strcpy(kto,"0750055500"); RETURN_OK_KTO_REPLACED;
                  case   900000: strcpy(kto,"0319966601"); RETURN_OK_KTO_REPLACED;
                  case   949494: strcpy(kto,"0575757500"); RETURN_OK_KTO_REPLACED;
                  case  1111111: strcpy(kto,"0448060000"); RETURN_OK_KTO_REPLACED;
                  case  7777777: strcpy(kto,"0443540000"); RETURN_OK_KTO_REPLACED;
                  case  9000000: strcpy(kto,"0319966601"); RETURN_OK_KTO_REPLACED;
                  case 70000000: strcpy(kto,"0750055500"); RETURN_OK_KTO_REPLACED;
               }
               break;

            case 75040062: 
               if(!k1 && k2==6008833){strcpy(kto,"0600883300"); RETURN_OK_KTO_REPLACED;}
               break;

            case 76040061: 
               if(!k1 && k2==2500000){strcpy(kto,"0482146800"); RETURN_OK_KTO_REPLACED;}
               break;

            case 79040047: 
               if(!k1 && k2==9696){strcpy(kto,"0680210200"); RETURN_OK_KTO_REPLACED;}
               break;

            case 79080052: 
               if(!k1 && k2==9696){strcpy(kto,"0300021700"); RETURN_OK_KTO_REPLACED;}
               break;

            case 85080000: 
               if(!k1 && k2==400000){strcpy(kto,"0459488501"); RETURN_OK_KTO_REPLACED;}
               break;

            case 86080000: 
               if(!k1){
                  if(k2==  1212){strcpy(kto,"0480375900"); RETURN_OK_KTO_REPLACED;}
                  if(k2==121200){strcpy(kto,"0480375900"); RETURN_OK_KTO_REPLACED;}
               }
               break;
         }

         /* Hinweis zu Prüfziffermethode 13:
          * Sofern die vorliegende Kontonummer nur 6- oder 7-stellig ist
          * (7-stellig: Stellen 1-3 gleich Null und Stelle 4 ungleich Null;
          * 6-stellig: Stellen 1-4 gleich Null und Stelle 5 ungleich Null),
          * wird unterstellt, dass das Unterkonto "00" fehlt und diese zwei
          * Ziffern ergänzt, so dass sich eine 8- oder 9-stellige
          * Kontonummer ergibt. Die ergänzte Unterkontonummer "00" wird bei
          * erfolgreichem Prüfzifferncheck auch in die IBAN übernommen.
          */
         if(pz_methode==13 && *kto=='0' && kto[1]=='0' && kto[2]=='0'
               && ( kto[3]!='0' || (kto[3]=='0' && kto[4]!='0'))){
            kto[1]=kto[3];
            kto[2]=kto[4];
            kto[3]=kto[5];
            kto[4]=kto[6];
            kto[5]=kto[7];
            kto[6]=kto[8];
            kto[7]=kto[9];
            kto[8]='0';
            kto[9]='0';
            if(kto_check_pz("13a",kto,NULL)>0)
               return OK_UNTERKONTO_ATTACHED;
            else
              return FALSE_UNTERKONTO_ATTACHED;
         }

         /* Hinweis für den Fall der Ausnahme in Prüfziffermethode 76:
          * Die Kontonummer soll unverändert im Eingabeformat geprüft
          * werden, d.h. es wird hier die Stelle 10 auf gültige Prüfziffer
          * getestet. Es soll nicht im Vorwege der Prüfung eine "00" an die
          * Kontonummer ergänzt werden. Analog zur Berechnungsmethode 13 ist
          * im Falle der beschriebenen Ausnahme (Prüfziffer auf Stelle 10)
          * ebenfalls eine ergänzte Unterkontonummer "00" in die IBAN zu
          * übernehmen.
          */
         if(pz_methode==76){
            if((ret=kto_check_pz("76a",kto,NULL))<OK && *kto=='0' && kto[1]=='0' && kto_check_pz("76b",kto,NULL)>0){
               kto[0]=kto[2];
               kto[1]=kto[3];
               kto[2]=kto[4];
               kto[3]=kto[5];
               kto[4]=kto[6];
               kto[5]=kto[7];
               kto[6]=kto[8];
               kto[7]=kto[9];
               kto[8]='0';
               kto[9]='0';
               return OK_UNTERKONTO_ATTACHED;
            }
            else  /* Methode 76a ergibt Fehler oder weniger als 2 führende Nullen */
               return ret;
         }

         RETURN_OK;   /* Zum Schluß noch ein Lumpensammler für alles, das übrig geblieben ist */


         /* Stadtsparkasse München */
      case 6:

         /* Umwandlung von Spendenkontonummern: */
         if(!k1)switch(k2){
            case 1111111:   strcpy(kto,"0020228888"); RETURN_OK_KTO_REPLACED;
            case 7777777:   strcpy(kto,"0903286003"); RETURN_OK_KTO_REPLACED;
            case 34343434:  strcpy(kto,"1000506517"); RETURN_OK_KTO_REPLACED;
            case 70000:     strcpy(kto,"0018180018"); RETURN_OK_KTO_REPLACED;
            default: RETURN_OK;
         }
         RETURN_OK;


         /* Sparkasse Köln-Bonn */
      case 7:

         /* Umwandlung von Spendenkontonummern: */
         if(k1==2){
            if(k2==820082){
               strcpy(kto,"1901783868");
               RETURN_OK_KTO_REPLACED;
            }
            if(k2==22220022){
               strcpy(kto,"0002222222");
               RETURN_OK_KTO_REPLACED;
            }
         }
         if(!k1)switch(k2){
            case 111:       strcpy(kto,"0000001115"); RETURN_OK_KTO_REPLACED;
            case 221:       strcpy(kto,"0023002157"); RETURN_OK_KTO_REPLACED;
            case 1888:      strcpy(kto,"0018882068"); RETURN_OK_KTO_REPLACED;
            case 2006:      strcpy(kto,"1900668508"); RETURN_OK_KTO_REPLACED;
            case 2626:      strcpy(kto,"1900730100"); RETURN_OK_KTO_REPLACED;
            case 3004:      strcpy(kto,"1900637016"); RETURN_OK_KTO_REPLACED;
            case 3636:      strcpy(kto,"0023002447"); RETURN_OK_KTO_REPLACED;
            case 4000:      strcpy(kto,"0000004028"); RETURN_OK_KTO_REPLACED;
            case 4444:      strcpy(kto,"0000017368"); RETURN_OK_KTO_REPLACED;
            case 5050:      strcpy(kto,"0000073999"); RETURN_OK_KTO_REPLACED;
            case 8888:      strcpy(kto,"1901335750"); RETURN_OK_KTO_REPLACED;
            case 30000:     strcpy(kto,"0009992959"); RETURN_OK_KTO_REPLACED;
            case 43430:     strcpy(kto,"1901693331"); RETURN_OK_KTO_REPLACED;
            case 46664:     strcpy(kto,"1900399856"); RETURN_OK_KTO_REPLACED;
            case 55555:     strcpy(kto,"0034407379"); RETURN_OK_KTO_REPLACED;
            case 102030:    strcpy(kto,"1900480466"); RETURN_OK_KTO_REPLACED;
            case 151515:    strcpy(kto,"0057762957"); RETURN_OK_KTO_REPLACED;
            case 222222:    strcpy(kto,"0002222222"); RETURN_OK_KTO_REPLACED;
            case 300000:    strcpy(kto,"0009992959"); RETURN_OK_KTO_REPLACED;
            case 333333:    strcpy(kto,"0000033217"); RETURN_OK_KTO_REPLACED;
            case 414141:    strcpy(kto,"0000092817"); RETURN_OK_KTO_REPLACED;
            case 606060:    strcpy(kto,"0000091025"); RETURN_OK_KTO_REPLACED;
            case 909090:    strcpy(kto,"0000090944"); RETURN_OK_KTO_REPLACED;
            case 2602024:   strcpy(kto,"0005602024"); RETURN_OK_KTO_REPLACED;
            case 3000000:   strcpy(kto,"0009992959"); RETURN_OK_KTO_REPLACED;
            case 7777777:   strcpy(kto,"0002222222"); RETURN_OK_KTO_REPLACED;
            case 8090100:   strcpy(kto,"0000038901"); RETURN_OK_KTO_REPLACED;
            case 14141414:  strcpy(kto,"0043597665"); RETURN_OK_KTO_REPLACED;
            case 15000023:  strcpy(kto,"0015002223"); RETURN_OK_KTO_REPLACED;
            case 15151515:  strcpy(kto,"0057762957"); RETURN_OK_KTO_REPLACED;
            case 22222222:  strcpy(kto,"0002222222"); RETURN_OK_KTO_REPLACED;
            default: RETURN_OK;
         }
         RETURN_OK;


         /* BHF-Bank AG */
      case 8:
         if(b==50020200)return OK;
         strcpy(blz,"50020200");
         *bicp="BHFBDEFF500";
         return OK_BLZ_REPLACED;


         /* Sparkasse Schopfheim-Zell */
      case 9:
         if(b==68351557)return OK;
         strcpy(blz,"68351557");
         *bicp="SOLADES1SFH";

         /* Bei Kontonummern der ehemaligen Sparkasse Zell im Wiesental (BLZ:
          * 683 519 76), die bei zehnstelliger Darstellung mit 1116 beginnen,
          * werden die linken vier Stellen durch den Wert 3047 ersetzt.
          */
         if(b==68351976 && kto[0]=='1' && kto[1]=='1' && kto[2]=='1' && kto[3]=='6'){
            kto[0]='3';
            kto[1]='0';
            kto[2]='4';
            kto[3]='7';
            return OK_BLZ_KTO_REPLACED;
         }
         return OK_BLZ_REPLACED;


         /* Frankfurter Sparkasse */
      case 10:

         if(b==50050222){  /* Ergänzung Email Bundesbank vom 1.8.13 */
            strcpy(blz,"50050201");
            ret=OK_BLZ_REPLACED;
            b=50050201;
         }
         else
            ret=OK;

            /* zwei Ausnahmen */
         if(b==50050201){
            if(!k1){
               if(k2==2000){
                  strcpy(kto,"0000222000");
                  if(ret==OK_BLZ_REPLACED)
                     return OK_BLZ_KTO_REPLACED;
                  else
                     RETURN_OK_KTO_REPLACED;
               }
               if(k2==800000){
                  strcpy(kto,"0000180802");
                  if(ret==OK_BLZ_REPLACED)
                     return OK_BLZ_KTO_REPLACED;
                  else
                     RETURN_OK_KTO_REPLACED;
               }
            }
         }
         return ret;


         /* Sparkasse Krefeld */
      case 11:

         /* zwei Spendenkontonummern */
         if(!k1)switch(k2){
            case 1000:
               strcpy(kto,"0008010001");
               RETURN_OK_KTO_REPLACED;
            case 47800:
               strcpy(kto,"0000047803");
               RETURN_OK_KTO_REPLACED;
            default:
               break;
         }
         RETURN_OK;


         /* Landesbank Hessen-Thüringen */
      case 12:

            /* Für die IBAN-Ermittlung ist stets die Bankleitzahl 500 500 00 zu verwenden. */
         if(b==50050000)return OK;
         strcpy(blz,"50050000");
         *bicp="HELADEFFXXX";
         return OK_BLZ_REPLACED;


         /* Landesbank Hessen-Thüringen */
      case 13:

            /* Für die IBAN-Ermittlung ist stets die Bankleitzahl 300 500 00 zu verwenden. */
         if(b==30050000)return OK;
         strcpy(blz,"30050000");
         *bicp="WELADEDDXXX";
         return OK_BLZ_REPLACED;


         /* Deutsche Apotheker- u. Ärztebank */
      case 14:

         /* Bei der Berechnung von IBAN und BIC für die Deutsche Apotheker-
          * und Ärztebank eG ist stets die zentrale Bankleitzahl für den
          * Hauptsitz Düsseldorf (BLZ 300 606 01) zu verwenden.
          */
         if(b==30060601)return OK;
         strcpy(blz,"30060601");
         *bicp="DAAEDEDDXXX";
         return OK_BLZ_REPLACED;


         /* Pax-Bank eG */
      case 15:

         /* einige Sonderkonten */
         if(k1==4 && k2==569017){
            strcpy(kto,"4000569017");
            RETURN_OK_KTO_REPLACED;
         }
         if(!k1)switch(k2){
            case 94:        strcpy(kto,"3008888018"); RETURN_OK_KTO_REPLACED;  /* Ergänzung Email Bundesbank vom 1.8.13 */
            case 556:       strcpy(kto,"0000101010"); RETURN_OK_KTO_REPLACED;
            case 888:       strcpy(kto,"0031870011"); RETURN_OK_KTO_REPLACED;
            case 4040:      strcpy(kto,"4003600101"); RETURN_OK_KTO_REPLACED;
            case 5826:      strcpy(kto,"1015826017"); RETURN_OK_KTO_REPLACED;
            case 25000:     strcpy(kto,"0025000110"); RETURN_OK_KTO_REPLACED;
            case 393393:    strcpy(kto,"0033013019"); RETURN_OK_KTO_REPLACED;
            case 444555:    strcpy(kto,"0032230016"); RETURN_OK_KTO_REPLACED;
            case 603060:    strcpy(kto,"6002919018"); RETURN_OK_KTO_REPLACED;
            case 2120041:   strcpy(kto,"0002130041"); RETURN_OK_KTO_REPLACED;
            case 80868086:  strcpy(kto,"4007375013"); RETURN_OK_KTO_REPLACED;
            default: break;
         }
         RETURN_OK;


         /* Kölner Bank eG */
      case 16:

            /* Sonderkonto */
         if(!k1 && k2==300000){
            strcpy(kto,"0018128012");
            RETURN_OK_KTO_REPLACED;
         }
         RETURN_OK;


         /* Volksbank Bonn Rhein-Sieg */
      case 17:

            /* einige Sonderkonten */
         if(!k1)switch(k2){
            case 100:       strcpy(kto,"2009090013"); RETURN_OK_KTO_REPLACED;
            case 111:       strcpy(kto,"2111111017"); RETURN_OK_KTO_REPLACED;
            case 240:       strcpy(kto,"2100240010"); RETURN_OK_KTO_REPLACED;
            case 4004:      strcpy(kto,"2204004016"); RETURN_OK_KTO_REPLACED;
            case 4444:      strcpy(kto,"2044444014"); RETURN_OK_KTO_REPLACED;
            case 6060:      strcpy(kto,"2016060014"); RETURN_OK_KTO_REPLACED;
            case 102030:    strcpy(kto,"1102030016"); RETURN_OK_KTO_REPLACED;
            case 333333:    strcpy(kto,"2033333016"); RETURN_OK_KTO_REPLACED;
            case 909090:    strcpy(kto,"2009090013"); RETURN_OK_KTO_REPLACED;
            case 50005000:  strcpy(kto,"5000500013"); RETURN_OK_KTO_REPLACED;
            default: break;
         }
         RETURN_OK;


         /* Aachener Bank eG */
      case 18:

            /* einige Sonderkonten */
         if(k1==54 && k2==35435430){
            strcpy(kto,"0543543543");
            RETURN_OK_KTO_REPLACED;
         }
         if(!k1)switch(k2){
            case 556:       strcpy(kto,"0120440110"); RETURN_OK_KTO_REPLACED;
            case 2157:      strcpy(kto,"0121787016"); RETURN_OK_KTO_REPLACED;
            case 9800:      strcpy(kto,"0120800019"); RETURN_OK_KTO_REPLACED;
            case 202050:    strcpy(kto,"1221864014"); RETURN_OK_KTO_REPLACED;
            default: break;
         }
         RETURN_OK;


         /* Bethmann Bank */
      case 19:

         if(b==50120383)return OK;
         strcpy(blz,"50120383");
         *bicp="DELBDE33XXX";
         return OK_BLZ_REPLACED;


         /* Deutsche Bank AG
          * Neuimplementierung nach der Regel-Version 1.6 (oder 1.5?) der Deutschen Bank vom 30.8.2013
          */
      case 20:

            /* BLZ ohne IBAN-Berechnung */
         if(b==10020000)return NO_IBAN_CALCULATION;

            /* Spendenkontonummer */
         if(b==50070010 && k1==0 && k2==9999){
            strcpy(kto,"0092777202");
            RETURN_OK_KTO_REPLACED;
         }

            /* Prüfziffermethode holen */
         if((idx=lut_index(blz))<0)return idx;
         pz_methode=pz_methoden[idx];

            /* Prüfzifferverfahren 09 (Deutsche Bank GF intern) */
         if(pz_methode==9)return OK_NO_CHK;

            /* Sonderfall Norisbank: Konten, bei denen ausschließlich das
             * Prüfzifferverfahren 06 eine gültige Prüfziffer liefern, sind für
             * die IBAN-Berechnung nicht zugelassen.
             */
         if(pz_methode==127 && kto_check_pz("c7a",kto,NULL)<OK && kto_check_pz("c7c",kto,NULL)<OK){
            if(retvals){
                  /* in retvals noch Werte für den Fehlerfall eintragen */
               retvals->methode="c7b";
               retvals->pz_methode=2127;
            }
            if((ret=kto_check_pz("c7b",kto,NULL))==OK)
               return NO_IBAN_CALCULATION;
            else
               return ret;
         }

            /* 10-stellige Konten sind ungültig */
         if(*kto!='0')return INVALID_KTO;

            /* jetzt kommt nur noch das Prüfzifferverfahren 63 (Deutsche Bank) */
         if(retvals){
            retvals->methode="63";
            retvals->pz_methode=63;
         }

         if(k1==0){  /* erstmal maximal 7-stellige Konten */
               /* 1-4 stellige Konten sind generell nicht zugelassen */
            if(k2<10000)return NO_IBAN_CALCULATION;

               /* bei 5- und 6stellige Konten werden rechts zwei Nullen
                * angefügt. Falls die Prüfziffer dann stimmt, wird diese
                * Kontonummer für die IBAN-Berechnung übernommen. Es dürfen
                * allerdings nicht noch einmal Nullen angehängt werden (d.h.
                * nur Prüfzifferverfahren 63a ist gültig).
                */
            if(k2<1000000){
                  /* zunächst einmal testen, ob das Konto mit Methode 63a
                   * gültig ist, um den Rückgabewert im Fehlerfall bei Methode
                   * 63b zu setzen. Falls 63a gültig ist, wird dann
                   * NO_IBAN_CALCULATION zurückgegeben.
                   *
                   * Falls hier nicht differenziert wird, würde beim normalen
                   * Kontentest OK zurückgegeben, beim Kontentest mit
                   * IBAN-Regeln jedoch FALSE, was etwas verwirrend ist.
                   */
               tmp=kto_check_pz("63a",kto,NULL);
               for(i=0;i<8;i++)kto[i]=kto[i+2];
               kto[8]='0';
               kto[9]='0';
               if((ret=kto_check_pz("63a",kto,NULL))==OK)
                  return OK_UNTERKONTO_ATTACHED;
               else{
                  if(retvals){
                        /* in retvals noch Werte für den Fehlerfall eintragen */
                     retvals->methode="63b";
                     retvals->pz_methode=2063;
                  }
                  if(tmp==OK) /* ursprüngliches Konto war mit 63a gültig */
                     return NO_IBAN_CALCULATION;
                  else
                     return ret;
               }
            }

               /* 7-stellige Konten: zuerst Unterkonto 00 anhängen (Vorschrift
                * aus Regel 20, Schritt c und d); falls das nicht klappt, mit
                * Regel 63a probieren.
               */
            if(k2>=1000000 && k2<10000000){
               if(kto_check_pz("63b",kto,NULL)==OK){
                  for(i=0;i<8;i++)kto[i]=kto[i+2];
                  kto[8]='0';
                  kto[9]='0';
                  return OK_UNTERKONTO_ATTACHED;
               }
               else
                  return kto_check_pz("63a",kto,NULL);
            }
         }

            /* alle restlichen Konten (8- bis 9-stellig) nur mit Methode 63a prüfen */
         return kto_check_pz("63a",kto,NULL);

         /* National-Bank AG */
      case 21:
            /* 1-5 stellige oder 8 stellige Konten sind ungültig */
         if(k1==0 && (k2<100000 || k2>9999999))return INVALID_KTO;
         if(b==36020030)return OK;
         strcpy(blz,"36020030");
         *bicp="NBAGDE3EXXX";
         return OK_BLZ_REPLACED;


         /* GLS Gemeinschaftsbank eG */
      case 22:

            /* Sonderkonto */
         if(!k1 && k2==1111111){
            strcpy(kto,"2222200000");
            RETURN_OK_KTO_REPLACED;
         }
         RETURN_OK;


         /* Volksbank Osnabrück eG */
      case 23:

            /* Sonderkonto */
         if(k1==0 && k2==700){
            strcpy(kto,"1000700800");
            RETURN_OK_KTO_REPLACED;
         }
         RETURN_OK;


         /* Bank im Bistum Essen eG */
      case 24:

            /* einige Sonderkonten */
         if(!k1)switch(k2){
            case 94:  strcpy(kto,"00001694"); RETURN_OK_KTO_REPLACED;
            case 248: strcpy(kto,"00017248"); RETURN_OK_KTO_REPLACED;
            case 345: strcpy(kto,"00017345"); RETURN_OK_KTO_REPLACED;
            case 400: strcpy(kto,"00014400"); RETURN_OK_KTO_REPLACED;
            default: break;
         }
         RETURN_OK;


         /* Landesbank Baden-Württemberg /Baden-Württembergische Bank */
      case 25:

         if(b==60050101)return OK;
         strcpy(blz,"60050101");
         *bicp="SOLADEST600";
         return OK_BLZ_REPLACED;


         /* Bank für Kirche und Diakonie eG */
      case 26:

            /* spezielle Sonderfälle: Für die Bankleitzahl 350 601 90 erfolgt
             * die IBAN-Berechnung nach der Standard-IBAN-Regel. Abweichend
             * hierzu kann aber für nachfolgend aufgeführte Konten die
             * IBAN-Berechnung durchgeführt werden, auch wenn die Kontrolle der
             * in der Kontonummer enthaltenen Prüfziffer fehlschlägt.
             */
         if(k1==0 && (k2==55111 || k2==8090100))return OK_IBAN_WITHOUT_KC_TEST;
         RETURN_OK;


         /* Volksbank Krefeld eG */
      case 27:

            /* Und gleich nochmal die gleichen Besonderheiten wie in Regel 26 ;-) */
         if(k1==0 && (k2==3333 || k2==4444))return OK_IBAN_WITHOUT_KC_TEST;
         RETURN_OK;


         /* Sparkasse Hannover */
      case 28:
         if(b==25050180)return OK;
         strcpy(blz,"25050180");
         *bicp="SPKHDE2HXXX";
         return OK_BLZ_REPLACED;


         /* Société Générale */
      case 29:

         /* 10-stellige Kontennummern (d. h. die 1. Ziffer der Kontonummer ist
          * ungleich "0"), die in Position 4 eine "0" enthalten, können nicht
          * 1:1 in eine gültige IBAN konvertiert werden.
          *
          * In diesen Fällen wird die korrekte Kontonummer für IBAN gebildet
          * indem die 4. Ziffer (die "0") entfernt wird. Man erhält eine
          * 9-stellige Konto-Nummer, die 1. Ziffer der Kontonummer in der IBAN
          * ist damit implizit eine "0".
          */
         if(*kto!='0' && *(kto+3)=='0'){
            kto[3]=kto[2];
            kto[2]=kto[1];
            kto[1]=*kto;
            *kto='0';
            RETURN_OK_KTO_REPLACED;
         }
         RETURN_OK;


         /* Pommersche Volksbank eG */
      case 30:

            /* diese Bank hat gleich eine lange Reihe Konten, die trotz
             * fehlerhafter Prüfziffer umzuwandeln sind. Der Einfachheit halber
             * werden die Kontonummern in zwei Teile aufgeteilt (die beiden
             * ersten Stellen und die restlichen 8); diese passen dann bequem
             * in zwei 32Bit-Integer und können über zwei geschachtelte
             * switch() Anweisungen verarbeitet werden.
             */
         switch(k1){
            case 0:
               switch(k2){
                  case  1718190: return OK_IBAN_WITHOUT_KC_TEST;
                  case 22000225: return OK_IBAN_WITHOUT_KC_TEST;
                  case 49902271: return OK_IBAN_WITHOUT_KC_TEST;
                  case 49902280: return OK_IBAN_WITHOUT_KC_TEST;
                  default: break;
               }
               break;

            case 1:
               switch(k2){
                  case 1680029: return OK_IBAN_WITHOUT_KC_TEST;
                  case 4200028: return OK_IBAN_WITHOUT_KC_TEST;
                  case 6200025: return OK_IBAN_WITHOUT_KC_TEST;
                  case 8000171: return OK_IBAN_WITHOUT_KC_TEST;
                  case 8000279: return OK_IBAN_WITHOUT_KC_TEST;
                  case 8001364: return OK_IBAN_WITHOUT_KC_TEST;
                  case 8001801: return OK_IBAN_WITHOUT_KC_TEST;
                  case 8002514: return OK_IBAN_WITHOUT_KC_TEST;
                  default: break;
               }
               break;

            case 3:
               if(k2==8542) return OK_IBAN_WITHOUT_KC_TEST;
               break;

            case 91:
               switch(k2){
                  case 30099995: return OK_IBAN_WITHOUT_KC_TEST;
                  case 30500002: return OK_IBAN_WITHOUT_KC_TEST;
                  case 31100008: return OK_IBAN_WITHOUT_KC_TEST;
                  case 31600000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 31610006: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32200006: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32400005: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32600004: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32700017: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32700025: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32700033: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32700041: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200700: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200735: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200743: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200751: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200786: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200808: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200816: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200824: return OK_IBAN_WITHOUT_KC_TEST;
                  case 33200832: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36700003: return OK_IBAN_WITHOUT_KC_TEST;
                  case 77300010: return OK_IBAN_WITHOUT_KC_TEST;
                  case 77300060: return OK_IBAN_WITHOUT_KC_TEST;
                  case 98100002: return OK_IBAN_WITHOUT_KC_TEST;
                  case 98200007: return OK_IBAN_WITHOUT_KC_TEST;
                  case 98200104: return OK_IBAN_WITHOUT_KC_TEST;
                  case 98300001: return OK_IBAN_WITHOUT_KC_TEST;
                  default: break;
               }
               break;

            case 93:
               switch(k2){
                  case 31300141: return OK_IBAN_WITHOUT_KC_TEST;
                  case 31300150: return OK_IBAN_WITHOUT_KC_TEST;
                  case 31401010: return OK_IBAN_WITHOUT_KC_TEST;
                  case 31401061: return OK_IBAN_WITHOUT_KC_TEST;
                  case 49010000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 49100000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 60500001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 64902007: return OK_IBAN_WITHOUT_KC_TEST;
                  case 66101001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 66104000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 70620030: return OK_IBAN_WITHOUT_KC_TEST;
                  case 70620080: return OK_IBAN_WITHOUT_KC_TEST;
                  case 71900010: return OK_IBAN_WITHOUT_KC_TEST;
                  case 73600005: return OK_IBAN_WITHOUT_KC_TEST;
                  default: break;
               }
               break;

            case 94:
               if(k2==2900021)return OK_IBAN_WITHOUT_KC_TEST;
               break;

            case 96:
               switch(k2){
                  case  5110000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 14001000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 15000016: return OK_IBAN_WITHOUT_KC_TEST;
                  case 15010003: return OK_IBAN_WITHOUT_KC_TEST;
                  case 18500036: return OK_IBAN_WITHOUT_KC_TEST;
                  case 31020000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32600051: return OK_IBAN_WITHOUT_KC_TEST;
                  case 32600060: return OK_IBAN_WITHOUT_KC_TEST;
                  case 35000012: return OK_IBAN_WITHOUT_KC_TEST;
                  case 35000020: return OK_IBAN_WITHOUT_KC_TEST;
                  case 35701002: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36010003: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36013002: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36016001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36018004: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36019000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36022001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36024004: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36025000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36027003: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36028000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36045001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36048000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36051001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36053004: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36120003: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36140004: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36150000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36320002: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36700000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 38120000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 39401100: return OK_IBAN_WITHOUT_KC_TEST;
                  case 39801001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 70010004: return OK_IBAN_WITHOUT_KC_TEST;
                  case 80610000: return OK_IBAN_WITHOUT_KC_TEST;
                  default: break;
               }
               break;

            case 97:
               switch(k2){
                  case  5010002: return OK_IBAN_WITHOUT_KC_TEST;
                  case  5403004: return OK_IBAN_WITHOUT_KC_TEST;
                  case  5404000: return OK_IBAN_WITHOUT_KC_TEST;
                  case  5509996: return OK_IBAN_WITHOUT_KC_TEST;
                  case  7901001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 36010000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 80100050: return OK_IBAN_WITHOUT_KC_TEST;
                  case 91000030: return OK_IBAN_WITHOUT_KC_TEST;
                  default: break;
               }
               break;

            case 99:
               switch(k2){
                  case 90001003: return OK_IBAN_WITHOUT_KC_TEST;
                  case 90001100: return OK_IBAN_WITHOUT_KC_TEST;
                  case 90002000: return OK_IBAN_WITHOUT_KC_TEST;
                  case 90004002: return OK_IBAN_WITHOUT_KC_TEST;
                  case 91020001: return OK_IBAN_WITHOUT_KC_TEST;
                  case 91040002: return OK_IBAN_WITHOUT_KC_TEST;
                  case 91060003: return OK_IBAN_WITHOUT_KC_TEST;
                  case 99999993: return OK_IBAN_WITHOUT_KC_TEST;
                  case 99999994: return OK_IBAN_WITHOUT_KC_TEST;
                  case 99999995: return OK_IBAN_WITHOUT_KC_TEST;
                  case 99999996: return OK_IBAN_WITHOUT_KC_TEST;
                  case 99999997: return OK_IBAN_WITHOUT_KC_TEST;
                  case 99999998: return OK_IBAN_WITHOUT_KC_TEST;
                  case 99999999: return OK_IBAN_WITHOUT_KC_TEST;
                  default: break;
               }
               break;
         }
         RETURN_OK;


         /* UniCredit Bank AG:
          * Diese Bank definiert fünf verschiedene Regeln, die teilweise
          * aufeinander aufbauen. Sie werden daher gemeinsam behandelt.
          */
      case 31:
      case 32:
      case 33:
      case 34:
      case 35:

         /* Berechnungsregel 31: Ehemalige HYPO-Bank
          * Wird eine Bankleitzahl mit Löschkennzeichen - erkennbar an
          * Kennzeichen "1" in Feld 12 der Bankleitzahlendatei - und mit dem
          * oben genannten IBAN-Kennzeichen - siehe Feld 14 der Bankleitzahlen-
          * datei - im Feld "Bankleitzahl" angeliefert, so ist die als Anlage
          * beigefügte Tabelle
          *
          * "Tabelle zu Kontokreise exHypo"
          *
          * anzufragen und anhand des genannten Kontokreises in der ersten
          * Spalte bzw. Kontonummernbereich "von-bis" in der dritten und vierten
          * Spalte die Nachfolge-Bankleitzahl zu ermitteln.
          *
          * Nur die ermittelte Nachfolge-BLZ darf zur IBAN-Berechnung verwendet werden.
          *
          * Achtung:
          *
          * * Diese Vorgehensweise gilt nur für 10-stellige Kontonummern!
          *
          * * Die Prüfziffer der Kontonummer ist zu prüfen!
          *
          * * Kürzere Kontonummern sind nicht zugelassen!
          *
          * * Diese IBAN-Regel überstimmt die in der Bankleitzahlendatei in Feld
          *   13 jeweils gemeldeten Nachfolge-Bankleitzahlen!
          *
          * * Es ist stets der BIC der ausgetauschten Bankleitzahl gemäß Eintrag
          *   in Feld 8 der Bankleitzahlendatei auszugeben.
          *
          ***************************************************************************
          *
          * Berechnungsregel 32: HYPO-Bank-Nachfolge
          * 
          * * Die IBAN-Regel Nr. 0032 ist das Gegenstück zu IBAN-Regel Nr. 0031
          *   und verdeutlicht die zugelassenen Kontokreise für die aufnehmenden
          *   Bankleitzahlen der ehemaligen HYPO-Bank.
          * 
          * * Bei Bankleitzahlen mit dem Kennzeichen 0032 - siehe Feld 14 der
          *   Bankleitzahlendatei - erfolgt die Anfrage nach zulässigen
          *   Kontonummern ebenfalls anhand der Tabelle "Tabelle zu Kontokreise
          *   exHypo", die der IBAN-Regel 0031 als Anlage beigefügt ist.
          * 
          * * Die Bankleitzahlen enthalten kein Löschkennzeichen in Feld 12 der
          *   Bankleitzahlendatei.
          * 
          * * Die IBAN-Regel Nr. 0032 gilt nur für 10-stellige Kontonummern.
          * 
          * * Kürzere Kontonummern sind zugelassen, im Rahmen der entsprechenden
          *   Prüfziffernberechnungsmethode - mit Ausnahme des Kontonummern-
          *   bereiches 800 000 000 bis 899 999 999.
          *
          ***************************************************************************
          *
          * Berechnungsregel 33: BLZ 700 202 70, UniCredit Bank München
          *
          * *  Die IBAN-Regel Nr. 0033 ist nur für die BLZ 700 202 70 gültig.
          *    Sie ist eine Kombination aus mehreren Besonderheiten:
          * 
          * a. Logik der IBAN-Regel Nr. 0032 in Bezug auf 10-stellige
          *    Kontonummernkreise: Die Tabelle "Tabelle zu Kontokreise exHypo",
          *    die der IBAN-Regel 0031 als Anlage beigefügt ist, ist zu
          *    berücksichtigen.
          * 
          * b. Kürzere Kontonummern sind zugelassen, im Rahmen der
          *    Prüfziffernberechnungsmethode:
          * 
          * c. Der Kontokreis 800 000 000 bis 899 999 999 ist allein unter BLZ
          *    700 202 70 gültig
          * 
          * d. Berücksichtigung von Pseudokontonummern:
          *    Bei den nachfolgenden Spendenkonten erfolgt die Anlieferung im
          *    Feld Konto-Nr. mit einer Pseudokontonummer. Diese ist durch die
          *    angegebene Kontonummer zur IBAN-Berechnung zu ersetzen.
          *    
          *    Pseudokonto     BLZ            reale Kontonummer
          *    22222           70020270       5803435253
          *    1111111         70020270       39908140
          *    94              70020270       2711931
          *    7777777         70020270       5800522694
          *    55555           70020270       5801800000
          *
          ***************************************************************************
          *
          * Berechnungsregel 34: BLZ 600 202 90, UniCredit Bank Stuttgart
          *
          * * Die IBAN-Regel Nr. 0034 ist nur für die BLZ 600 202 90 gültig.
          *
          * * Sie ist eine Kombination aus mehreren Besonderheiten:
          *
          * a. Logik der IBAN-Regel Nr. 0032 in Bezug auf 10-stellige
          *    Kontonummernkreise:
          *    Die Tabelle "Tabelle zu Kontokreise exHypo", die der IBAN-Regel
          *    0031 als Anlage beigefügt ist, ist zu berücksichtigen.
          *
          * b. Kürzere Kontonummern sind zugelassen, im Rahmen der
          *    Prüfziffernberechnungsmethode.
          * 
          * c. Der Kontokreis 800 000 000 bis 899 999 999 ist nicht zugelassen.
          * 
          * d. Berücksichtigung von Pseudokontonummern:
          *    Bei den nachfolgenden Spendenkonten erfolgt die Anlieferung im
          *    Feld Konto-Nr. mit einer Pseudokontonummer. Diese ist durch die
          *    angegebene Kontonummer zur IBAN-Berechnung zu ersetzen.
          *    
          *    Pseudokonto     BLZ            reale Kontonummer
          *    500500500       60020290       4340111112
          *    502             60020290       4340118001
          *
          ***************************************************************************
          *
          * 
          * Berechnungsregel 35: BLZ 790 200 76, UniCredit Bank Würzburg
          * 
          * * Die IBAN-Regel Nr. 0035 ist nur für die BLZ 790 200 76 gültig.
          * 
          * * Sie ist eine Kombination aus mehreren Besonderheiten:
          * 
          * a. Logik der IBAN-Regel Nr. 0032 in Bezug auf 10-stellige
          *    Kontonummernkreise:
          *    Die Tabelle "Tabelle zu Kontokreise exHypo", die der IBAN-Regel
          *    0031 als Anlage beigefügt ist, ist zu berücksichtigen.
          *
          * b. Kürzere Kontonummern sind zugelassen, im Rahmen der
          *    Prüfziffernberechnungsmethode:
          * 
          * c. Der Kontokreis 800 000 000 bis 899 999 999 ist nicht zugelassen.
          * 
          * d. Berücksichtigung von Pseudokontonummern:
          *    Bei dem nachfolgenden Spendenkonto erfolgt die Anlieferung im
          *    Feld Konto-Nr. Hin mit einer Pseudokontonummer. Diese ist durch
          *    die angegebene Kontonummer zur IBAN-Berechnung zu ersetzen.
          *
          *    Pseudokonto     BLZ            reale Kontonummer
          *    9696            79020076       1490196966
          * 
          *****************************************************************************
          *****************************************************************************
          **                                                                         **
          ** Kurzfassung der Regeln 31-35:                                           **
          **                                                                         **
          ** 31:                                                                     **
          **    - mit Löschkennzeichen                                               **
          **    - 10-stellige Konten mit "Tabelle Kontokreise exHypo"                **
          **    - kürzere Kontonummern nicht zugelassen                              **
          **                                                                         **
          ** 32:                                                                     **
          **    - kein Löschkennzeichen                                              **
          **    - 10-stellige Konten mit "Tabelle Kontokreise exHypo"                **
          **    - kürzere Kontonummern zugelassen                                    **
          **    - Kontokreis 800 000 000 bis 899 999 999 nicht zugelassen            **
          **                                                                         **
          ** 33:                                                                     **
          **    - nur für BLZ 700 202 70 gültig                                      **
          **    - 10-stellige Konten mit "Tabelle Kontokreise exHypo"                **
          **    - kürzere Kontonummern zugelassen                                    **
          **    - Kontokreis 800 000 000 bis 899 999 999 zugelassen                  **
          **    - Spendenkonten                                                      **
          **                                                                         **
          ** 34:                                                                     **
          **    - nur für BLZ 600 202 90 gültig                                      **
          **    - 10-stellige Konten mit "Tabelle Kontokreise exHypo"                **
          **    - kürzere Kontonummern zugelassen                                    **
          **    - Kontokreis 800 000 000 bis 899 999 999 nicht zugelassen            **
          **    - Spendenkonten                                                      **
          **                                                                         **
          ** 35:                                                                     **
          **    - nur für BLZ 790 200 76 gültig                                      **
          **    - 10-stellige Konten mit "Tabelle Kontokreise exHypo"                **
          **    - kürzere Kontonummern zugelassen                                    **
          **    - Kontokreis 800 000 000 bis 899 999 999 nicht zugelassen            **
          **    - Spendenkonten                                                      **
          **                                                                         **
          *****************************************************************************
          *****************************************************************************
          */

         loesch=lut_loeschung(blz,0,&ret)=='1'?1:0;
         if(ret<OK)return ret;
         if(!(    /* Spendenkonten nicht testen */
                  (regel==33 &&   k1==0 && (k2==22222 || k2==1111111 || k2==94 || k2==7777777 || k2==55555))   /* Spendenkonten Regel 33 */
               || (regel==34 && ((k1==0 &&  k2==502) || (k1==5 && k2==500500)))   /* Spendenkonten Regel 34 */
               || (regel==35 &&   k1==0 &&  k2==9696))   /* Spendenkonten Regel 35 */
               && (ret=kto_check_blz(blz,kto))<OK)return ret;

         switch(regel){
            case 31:
               if(!loesch){
                  regel=32; /* Testfall D bei IBAN-Regel 31 */
                  if(k1==8)return NO_IBAN_CALCULATION; /* k2>=0 && k2<=99999999 ist implizit */
                  break;
               }
               else
                  if(*kto=='0')return NO_IBAN_CALCULATION;  /* 31: nur 10-stellige Konten */
               break;

            case 32:
               if(loesch)return IBAN_INVALID_RULE;
               if(k1==8)return NO_IBAN_CALCULATION; /* k2>=0 && k2<=99999999 ist implizit */
               break;

            case 33:
               if(b!=70020270)return IBAN_INVALID_RULE;
               if(!k1)switch(k2){
                  case 22222:    strcpy(kto,"5803435253"); RETURN_OK_KTO_REPLACED;
                  case 1111111:  strcpy(kto,"0039908140"); RETURN_OK_KTO_REPLACED;
                  case 94:       strcpy(kto,"0002711931"); RETURN_OK_KTO_REPLACED;
                  case 7777777:  strcpy(kto,"5800522694"); RETURN_OK_KTO_REPLACED;
                  case 55555:    strcpy(kto,"5801800000"); RETURN_OK_KTO_REPLACED;
                  default: break;
               }
               break;

            case 34:
               if(b!=60020290)return IBAN_INVALID_RULE;
               if(k1==8)return NO_IBAN_CALCULATION; /* k2>=0 && k2<=99999999 ist implizit */

                  /* Spendenkonten */
               if(k1==5 && k2==500500){
                  strcpy(kto,"4340111112");
                  RETURN_OK_KTO_REPLACED;
               }
               if(k1==0 && k2==502){
                  strcpy(kto,"4340118001");
                  RETURN_OK_KTO_REPLACED;
               }
               break;

            case 35:
               if(b!=79020076)return IBAN_INVALID_RULE;
               if(k1==8)return NO_IBAN_CALCULATION; /* k2>=0 && k2<=99999999 ist implizit */

                  /* Spendenkonto */
               if(k1==0 && k2==9696){
                  strcpy(kto,"1490196966");
                  RETURN_OK_KTO_REPLACED;
               }
               break;

            default:
               break;
         }

            /* Abschließend für 10-stellige Kontonummern die Nachfolge-BLZ aus dem
             * Kontokreis bestimmen (dies ist die "Tabelle zu Kontokreise exHypo").
             * Diese Ersetzung gilt für die Regeln 31 bis 35.
             */
         if(*kto!='0'){
            k3=b3[I kto[0]]+b2[I kto[1]]+b1[I kto[2]];   /* Kontokreis */
            switch(k3){
               case 100:
                  strcpy(blz,"76020070");
                  break;
               case 101:
                  strcpy(blz,"10020890");
                  break;
               case 102:
                  strcpy(blz,"78320076");
                  break;
               case 103:
                  strcpy(blz,"79320075");
                  break;
               case 104:
                  strcpy(blz,"76320072");
                  break;
               case 105:
                  strcpy(blz,"79020076");
                  break;
               case 106:
                  strcpy(blz,"79320075");
                  break;
               case 107:
                  strcpy(blz,"79320075");
                  break;
               case 108:
                  strcpy(blz,"77320072");
                  break;
               case 109:
                  strcpy(blz,"79320075");
                  break;
               case 110:
                  strcpy(blz,"76220073");
                  break;
               case 111:
                  strcpy(blz,"76020070");
                  break;
               case 112:
                  strcpy(blz,"79320075");
                  break;
               case 113:
                  strcpy(blz,"76020070");
                  break;
               case 114:
                  strcpy(blz,"76020070");
                  break;
               case 115:
                  strcpy(blz,"76520071");
                  break;
               case 117:
                  strcpy(blz,"77120073");
                  break;
               case 118:
                  strcpy(blz,"76020070");
                  break;
               case 119:
                  strcpy(blz,"75320075");
                  break;
               case 120:
                  strcpy(blz,"72120078");
                  break;
               case 121:
                  strcpy(blz,"76220073");
                  break;
               case 122:
                  strcpy(blz,"76320072");
                  break;
               case 123:
                  strcpy(blz,"76420080");
                  break;
               case 124:
                  strcpy(blz,"76320072");
                  break;
               case 125:
                  strcpy(blz,"79520070");
                  break;
               case 126:
                  strcpy(blz,"77320072");
                  break;
               case 127:
                  strcpy(blz,"78020070");
                  break;
               case 128:
                  strcpy(blz,"78020070");
                  break;
               case 129:
                  strcpy(blz,"77120073");
                  break;
               case 130:
                  strcpy(blz,"78020070");
                  break;
               case 131:
                  strcpy(blz,"78020070");
                  break;
               case 132:
                  strcpy(blz,"60020290");
                  break;
               case 134:
                  strcpy(blz,"78020070");
                  break;
               case 135:
                  strcpy(blz,"77020070");
                  break;
               case 136:
                  strcpy(blz,"79520070");
                  break;
               case 137:
                  strcpy(blz,"79320075");
                  break;
               case 138:
                  strcpy(blz,"61120286");
                  break;
               case 139:
                  strcpy(blz,"66020286");
                  break;
               case 140:
                  strcpy(blz,"79020076");
                  break;
               case 142:
                  strcpy(blz,"64020186");
                  break;
               case 143:
                  strcpy(blz,"60020290");
                  break;
               case 144:
                  strcpy(blz,"79020076");
                  break;
               case 145:
                  strcpy(blz,"66020286");
                  break;
               case 146:
                  strcpy(blz,"72120078");
                  break;
               case 147:
                  strcpy(blz,"72223182");
                  break;
               case 148:
                  strcpy(blz,"76520071");
                  break;
               case 149:
                  strcpy(blz,"79020076");
                  break;
               case 150:
                  strcpy(blz,"76020070");
                  break;
               case 151:
                  strcpy(blz,"76320072");
                  break;
               case 152:
                  strcpy(blz,"78320076");
                  break;
               case 154:
                  strcpy(blz,"70020270");
                  break;
               case 155:
                  strcpy(blz,"76520071");
                  break;
               case 156:
                  strcpy(blz,"76020070");
                  break;
               case 157:
                  strcpy(blz,"10020890");
                  break;
               case 158:
                  strcpy(blz,"70020270");
                  break;
               case 159:
                  strcpy(blz,"54520194");
                  break;
               case 160:
                  strcpy(blz,"70020270");
                  break;
               case 161:
                  strcpy(blz,"54520194");
                  break;
               case 162:
                  strcpy(blz,"70020270");
                  break;
               case 163:
                  strcpy(blz,"70020270");
                  break;
               case 164:
                  strcpy(blz,"70020270");
                  break;
               case 166:
                  strcpy(blz,"71120078");
                  break;
               case 167:
                  strcpy(blz,"74320073");
                  break;
               case 168:
                  strcpy(blz,"70320090");
                  break;
               case 169:
                  strcpy(blz,"79020076");
                  break;
               case 170:
                  strcpy(blz,"70020270");
                  break;
               case 172:
                  strcpy(blz,"70020270");
                  break;
               case 174:
                  strcpy(blz,"70020270");
                  break;
               case 175:
                  strcpy(blz,"72120078");
                  break;
               case 176:
                  strcpy(blz,"74020074");
                  break;
               case 177:
                  strcpy(blz,"74320073");
                  break;
               case 178:
                  strcpy(blz,"70020270");
                  break;
               case 181:
                  strcpy(blz,"77320072");
                  break;
               case 182:
                  strcpy(blz,"79520070");
                  break;
               case 183:
                  strcpy(blz,"70020270");
                  break;
               case 185:
                  strcpy(blz,"70020270");
                  break;
               case 186:
                  strcpy(blz,"79020076");
                  break;
               case 188:
                  strcpy(blz,"70020270");
                  break;
               case 189:
                  strcpy(blz,"70020270");
                  break;
               case 190:
                  strcpy(blz,"76020070");
                  break;
               case 191:
                  strcpy(blz,"77020070");
                  break;
               case 192:
                  strcpy(blz,"70025175");
                  break;
               case 193:
                  strcpy(blz,"85020086");
                  break;
               case 194:
                  strcpy(blz,"76020070");
                  break;
               case 196:
                  strcpy(blz,"72020070");
                  break;
               case 198:
                  strcpy(blz,"76320072");
                  break;
               case 199:
                  strcpy(blz,"70020270");
                  break;
               case 201:
                  strcpy(blz,"76020070");
                  break;
               case 202:
                  strcpy(blz,"76020070");
                  break;
               case 203:
                  strcpy(blz,"76020070");
                  break;
               case 204:
                  strcpy(blz,"76020070");
                  break;
               case 205:
                  strcpy(blz,"79520070");
                  break;
               case 206:
                  strcpy(blz,"79520070");
                  break;
               case 207:
                  strcpy(blz,"71120078");
                  break;
               case 208:
                  strcpy(blz,"73120075");
                  break;
               case 209:
                  strcpy(blz,"18020086");
                  break;
               case 210:
                  strcpy(blz,"10020890");
                  break;
               case 211:
                  strcpy(blz,"60020290");
                  break;
               case 212:
                  strcpy(blz,"51020186");
                  break;
               case 214:
                  strcpy(blz,"75020073");
                  break;
               case 215:
                  strcpy(blz,"63020086");
                  break;
               case 216:
                  strcpy(blz,"75020073");
                  break;
               case 217:
                  strcpy(blz,"79020076");
                  break;
               case 218:
                  strcpy(blz,"59020090");
                  break;
               case 219:
                  strcpy(blz,"79520070");
                  break;
               case 220:
                  strcpy(blz,"73322380");
                  break;
               case 221:
                  strcpy(blz,"73120075");
                  break;
               case 222:
                  strcpy(blz,"73421478");
                  break;
               case 223:
                  strcpy(blz,"74320073");
                  break;
               case 224:
                  strcpy(blz,"73322380");
                  break;
               case 225:
                  strcpy(blz,"74020074");
                  break;
               case 227:
                  strcpy(blz,"75020073");
                  break;
               case 228:
                  strcpy(blz,"71120078");
                  break;
               case 229:
                  strcpy(blz,"80020086");
                  break;
               case 230:
                  strcpy(blz,"72120078");
                  break;
               case 231:
                  strcpy(blz,"72020070");
                  break;
               case 232:
                  strcpy(blz,"75021174");
                  break;
               case 233:
                  strcpy(blz,"71020072");
                  break;
               case 234:
                  strcpy(blz,"71022182");
                  break;
               case 235:
                  strcpy(blz,"74320073");
                  break;
               case 236:
                  strcpy(blz,"71022182");
                  break;
               case 237:
                  strcpy(blz,"76020070");
                  break;
               case 238:
                  strcpy(blz,"63020086");
                  break;
               case 239:
                  strcpy(blz,"70020270");
                  break;
               case 240:
                  strcpy(blz,"75320075");
                  break;
               case 241:
                  strcpy(blz,"76220073");
                  break;
               case 243:
                  strcpy(blz,"72020070");
                  break;
               case 245:
                  strcpy(blz,"72120078");
                  break;
               case 246:
                  strcpy(blz,"74320073");
                  break;
               case 247:
                  strcpy(blz,"60020290");
                  break;
               case 248:
                  strcpy(blz,"85020086");
                  break;
               case 249:
                  strcpy(blz,"73321177");
                  break;
               case 250:
                  strcpy(blz,"73420071");
                  break;
               case 251:
                  strcpy(blz,"70020270");
                  break;
               case 252:
                  strcpy(blz,"70020270");
                  break;
               case 253:
                  strcpy(blz,"70020270");
                  break;
               case 254:
                  strcpy(blz,"10020890");
                  break;
               case 255:
                  strcpy(blz,"50820292");
                  break;
               case 256:
                  strcpy(blz,"71022182");
                  break;
               case 257:
                  strcpy(blz,"83020086");
                  break;
               case 258:
                  strcpy(blz,"79320075");
                  break;
               case 259:
                  strcpy(blz,"71120077");
                  break;
               case 260:
                  strcpy(blz,"10020890");
                  break;
               case 261:
                  strcpy(blz,"70025175");
                  break;
               case 262:
                  strcpy(blz,"72020070");
                  break;
               case 264:
                  strcpy(blz,"74020074");
                  break;
               case 267:
                  strcpy(blz,"63020086");
                  break;
               case 268:
                  strcpy(blz,"70320090");
                  break;
               case 269:
                  strcpy(blz,"71122183");
                  break;
               case 270:
                  strcpy(blz,"82020086");
                  break;
               case 271:
                  strcpy(blz,"75020073");
                  break;
               case 272:
                  strcpy(blz,"73420071");
                  break;
               case 274:
                  strcpy(blz,"63020086");
                  break;
               case 276:
                  strcpy(blz,"70020270");
                  break;
               case 277:
                  strcpy(blz,"74320073");
                  break;
               case 278:
                  strcpy(blz,"71120077");
                  break;
               case 279:
                  strcpy(blz,"10020890");
                  break;
               case 281:
                  strcpy(blz,"71120078");
                  break;
               case 282:
                  strcpy(blz,"70020270");
                  break;
               case 283:
                  strcpy(blz,"72020070");
                  break;
               case 284:
                  strcpy(blz,"79320075");
                  break;
               case 286:
                  strcpy(blz,"54520194");
                  break;
               case 287:
                  strcpy(blz,"70020270");
                  break;
               case 288:
                  strcpy(blz,"75220070");
                  break;
               case 291:
                  strcpy(blz,"77320072");
                  break;
               case 292:
                  strcpy(blz,"76020070");
                  break;
               case 293:
                  strcpy(blz,"72020070");
                  break;
               case 294:
                  strcpy(blz,"54520194");
                  break;
               case 295:
                  strcpy(blz,"70020270");
                  break;
               case 296:
                  strcpy(blz,"70020270");
                  break;
               case 299:
                  strcpy(blz,"72020070");
                  break;
               case 301:
                  strcpy(blz,"85020086");
                  break;
               case 302:
                  strcpy(blz,"54520194");
                  break;
               case 304:
                  strcpy(blz,"70020270");
                  break;
               case 308:
                  strcpy(blz,"70020270");
                  break;
               case 309:
                  strcpy(blz,"54520194");
                  break;
               case 310:
                  strcpy(blz,"72020070");
                  break;
               case 312:
                  strcpy(blz,"74120071");
                  break;
               case 313:
                  strcpy(blz,"76320072");
                  break;
               case 314:
                  strcpy(blz,"70020270");
                  break;
               case 315:
                  strcpy(blz,"70020270");
                  break;
               case 316:
                  strcpy(blz,"70020270");
                  break;
               case 317:
                  strcpy(blz,"70020270");
                  break;
               case 318:
                  strcpy(blz,"70020270");
                  break;
               case 320:
                  strcpy(blz,"71022182");
                  break;
               case 321:
                  strcpy(blz,"75220070");
                  break;
               case 322:
                  strcpy(blz,"79520070");
                  break;
               case 324:
                  strcpy(blz,"70020270");
                  break;
               case 326:
                  strcpy(blz,"85020086");
                  break;
               case 327:
                  strcpy(blz,"72020070");
                  break;
               case 328:
                  strcpy(blz,"72020070");
                  break;
               case 329:
                  strcpy(blz,"70020270");
                  break;
               case 330:
                  strcpy(blz,"76020070");
                  break;
               case 331:
                  strcpy(blz,"70020270");
                  break;
               case 333:
                  strcpy(blz,"70020270");
                  break;
               case 334:
                  strcpy(blz,"75020073");
                  break;
               case 335:
                  strcpy(blz,"70020270");
                  break;
               case 337:
                  strcpy(blz,"80020086");
                  break;
               case 341:
                  strcpy(blz,"10020890");
                  break;
               case 342:
                  strcpy(blz,"10020890");
                  break;
               case 344:
                  strcpy(blz,"70020270");
                  break;
               case 345:
                  strcpy(blz,"77020070");
                  break;
               case 346:
                  strcpy(blz,"76020070");
                  break;
               case 350:
                  strcpy(blz,"79320075");
                  break;
               case 351:
                  strcpy(blz,"79320075");
                  break;
               case 352:
                  strcpy(blz,"70020270");
                  break;
               case 353:
                  strcpy(blz,"70020270");
                  break;
               case 354:
                  strcpy(blz,"72223182");
                  break;
               case 355:
                  strcpy(blz,"72020070");
                  break;
               case 356:
                  strcpy(blz,"70020270");
                  break;
               case 358:
                  strcpy(blz,"54220091");
                  break;
               case 359:
                  strcpy(blz,"76220073");
                  break;
               case 360:
                  strcpy(blz,"80020087");
                  break;
               case 361:
                  strcpy(blz,"70020270");
                  break;
               case 362:
                  strcpy(blz,"70020270");
                  break;
               case 363:
                  strcpy(blz,"70020270");
                  break;
               case 366:
                  strcpy(blz,"72220074");
                  break;
               case 367:
                  strcpy(blz,"70020270");
                  break;
               case 368:
                  strcpy(blz,"10020890");
                  break;
               case 369:
                  strcpy(blz,"76520071");
                  break;
               case 370:
                  strcpy(blz,"85020086");
                  break;
               case 371:
                  strcpy(blz,"70020270");
                  break;
               case 373:
                  strcpy(blz,"70020270");
                  break;
               case 374:
                  strcpy(blz,"73120075");
                  break;
               case 375:
                  strcpy(blz,"70020270");
                  break;
               case 379:
                  strcpy(blz,"70020270");
                  break;
               case 380:
                  strcpy(blz,"70020270");
                  break;
               case 381:
                  strcpy(blz,"70020270");
                  break;
               case 382:
                  strcpy(blz,"79520070");
                  break;
               case 383:
                  strcpy(blz,"72020070");
                  break;
               case 384:
                  strcpy(blz,"72020070");
                  break;
               case 386:
                  strcpy(blz,"70020270");
                  break;
               case 387:
                  strcpy(blz,"70020270");
                  break;
               case 389:
                  strcpy(blz,"70020270");
                  break;
               case 390:
                  strcpy(blz,"67020190");
                  break;
               case 391:
                  strcpy(blz,"70020270");
                  break;
               case 392:
                  strcpy(blz,"70020270");
                  break;
               case 393:
                  strcpy(blz,"54520194");
                  break;
               case 394:
                  strcpy(blz,"70020270");
                  break;
               case 396:
                  strcpy(blz,"70020270");
                  break;
               case 398:
                  strcpy(blz,"66020286");
                  break;
               case 399:
                  strcpy(blz,"87020088");
                  break;
               case 401:
                  strcpy(blz,"30220190");
                  break;
               case 402:
                  strcpy(blz,"36020186");
                  break;
               case 403:
                  strcpy(blz,"38020090");
                  break;
               case 404:
                  strcpy(blz,"30220190");
                  break;
               case 405:
                  strcpy(blz,"68020186");
                  break;
               case 406:
                  strcpy(blz,"48020086");
                  break;
               case 407:
                  strcpy(blz,"37020090");
                  break;
               case 408:
                  strcpy(blz,"68020186");
                  break;
               case 409:
                  strcpy(blz,"10020890");
                  break;
               case 410:
                  strcpy(blz,"66020286");
                  break;
               case 411:
                  strcpy(blz,"60420186");
                  break;
               case 412:
                  strcpy(blz,"57020086");
                  break;
               case 422:
                  strcpy(blz,"70020270");
                  break;
               case 423:
                  strcpy(blz,"70020270");
                  break;
               case 424:
                  strcpy(blz,"76020070");
                  break;
               case 426:
                  strcpy(blz,"70025175");
                  break;
               case 427:
                  strcpy(blz,"50320191");
                  break;
               case 428:
                  strcpy(blz,"70020270");
                  break;
               case 429:
                  strcpy(blz,"85020086");
                  break;
               case 432:
                  strcpy(blz,"70020270");
                  break;
               case 434:
                  strcpy(blz,"60020290");
                  break;
               case 435:
                  strcpy(blz,"76020070");
                  break;
               case 436:
                  strcpy(blz,"76020070");
                  break;
               case 437:
                  strcpy(blz,"70020270");
                  break;
               case 438:
                  strcpy(blz,"70020270");
                  break;
               case 439:
                  strcpy(blz,"70020270");
                  break;
               case 440:
                  strcpy(blz,"70020270");
                  break;
               case 441:
                  strcpy(blz,"70020270");
                  break;
               case 442:
                  strcpy(blz,"85020086");
                  break;
               case 443:
                  strcpy(blz,"55020486");
                  break;
               case 444:
                  strcpy(blz,"50520190");
                  break;
               case 446:
                  strcpy(blz,"80020086");
                  break;
               case 447:
                  strcpy(blz,"70020270");
                  break;
               case 450:
                  strcpy(blz,"30220190");
                  break;
               case 451:
                  strcpy(blz,"44020090");
                  break;
               case 452:
                  strcpy(blz,"70020270");
                  break;
               case 453:
                  strcpy(blz,"70020270");
                  break;
               case 456:
                  strcpy(blz,"10020890");
                  break;
               case 457:
                  strcpy(blz,"87020086");
                  break;
               case 458:
                  strcpy(blz,"54520194");
                  break;
               case 459:
                  strcpy(blz,"61120286");
                  break;
               case 460:
                  strcpy(blz,"70020270");
                  break;
               case 461:
                  strcpy(blz,"70020270");
                  break;
               case 462:
                  strcpy(blz,"70020270");
                  break;
               case 463:
                  strcpy(blz,"70020270");
                  break;
               case 465:
                  strcpy(blz,"70020270");
                  break;
               case 466:
                  strcpy(blz,"10020890");
                  break;
               case 467:
                  strcpy(blz,"10020890");
                  break;
               case 468:
                  strcpy(blz,"70020270");
                  break;
               case 469:
                  strcpy(blz,"60320291");
                  break;
               case 470:
                  strcpy(blz,"65020186");
                  break;
               case 471:
                  strcpy(blz,"84020087");
                  break;
               case 472:
                  strcpy(blz,"76020070");
                  break;
               case 473:
                  strcpy(blz,"74020074");
                  break;
               case 476:
                  strcpy(blz,"78320076");
                  break;
               case 477:
                  strcpy(blz,"78320076");
                  break;
               case 478:
                  strcpy(blz,"87020088");
                  break;
               case 480:
                  strcpy(blz,"70020270");
                  break;
               case 481:
                  strcpy(blz,"70020270");
                  break;
               case 482:
                  strcpy(blz,"84020087");
                  break;
               case 484:
                  strcpy(blz,"70020270");
                  break;
               case 485:
                  strcpy(blz,"50320191");
                  break;
               case 486:
                  strcpy(blz,"70020270");
                  break;
               case 488:
                  strcpy(blz,"67220286");
                  break;
               case 489:
                  strcpy(blz,"10020890");
                  break;
               case 490:
                  strcpy(blz,"10020890");
                  break;
               case 491:
                  strcpy(blz,"16020086");
                  break;
               case 492:
                  strcpy(blz,"10020890");
                  break;
               case 494:
                  strcpy(blz,"79020076");
                  break;
               case 495:
                  strcpy(blz,"87020088");
                  break;
               case 497:
                  strcpy(blz,"87020087");
                  break;
               case 499:
                  strcpy(blz,"79020076");
                  break;
               case 502:
                  strcpy(blz,"10020890");
                  break;
               case 503:
                  strcpy(blz,"10020890");
                  break;
               case 505:
                  strcpy(blz,"70020270");
                  break;
               case 506:
                  strcpy(blz,"10020890");
                  break;
               case 507:
                  strcpy(blz,"87020086");
                  break;
               case 508:
                  strcpy(blz,"86020086");
                  break;
               case 509:
                  strcpy(blz,"83020087");
                  break;
               case 510:
                  strcpy(blz,"80020086");
                  break;
               case 511:
                  strcpy(blz,"83020086");
                  break;
               case 513:
                  strcpy(blz,"85020086");
                  break;
               case 515:
                  strcpy(blz,"17020086");
                  break;
               case 518:
                  strcpy(blz,"82020086");
                  break;
               case 519:
                  strcpy(blz,"83020086");
                  break;
               case 522:
                  strcpy(blz,"10020890");
                  break;
               case 523:
                  strcpy(blz,"70020270");
                  break;
               case 524:
                  strcpy(blz,"85020086");
                  break;
               case 525:
                  strcpy(blz,"70020270");
                  break;
               case 527:
                  strcpy(blz,"82020088");
                  break;
               case 528:
                  strcpy(blz,"10020890");
                  break;
               case 530:
                  strcpy(blz,"10020890");
                  break;
               case 531:
                  strcpy(blz,"10020890");
                  break;
               case 533:
                  strcpy(blz,"50320191");
                  break;
               case 534:
                  strcpy(blz,"70020270");
                  break;
               case 536:
                  strcpy(blz,"85020086");
                  break;
               case 538:
                  strcpy(blz,"82020086");
                  break;
               case 540:
                  strcpy(blz,"65020186");
                  break;
               case 541:
                  strcpy(blz,"80020087");
                  break;
               case 545:
                  strcpy(blz,"18020086");
                  break;
               case 546:
                  strcpy(blz,"10020890");
                  break;
               case 547:
                  strcpy(blz,"10020890");
                  break;
               case 548:
                  strcpy(blz,"10020890");
                  break;
               case 549:
                  strcpy(blz,"82020087");
                  break;
               case 555:
                  strcpy(blz,"79020076");
                  break;
               case 560:
                  strcpy(blz,"79320075");
                  break;
               case 567:
                  strcpy(blz,"86020086");
                  break;
               case 572:
                  strcpy(blz,"10020890");
                  break;
               case 580:
                  strcpy(blz,"70020270");
                  break;
               case 581:
                  strcpy(blz,"70020270");
                  break;
               case 601:
                  strcpy(blz,"74320073");
                  break;
               case 602:
                  strcpy(blz,"70020270");
                  break;
               case 603:
                  strcpy(blz,"70020270");
                  break;
               case 604:
                  strcpy(blz,"70020270");
                  break;
               case 605:
                  strcpy(blz,"70020270");
                  break;
               case 606:
                  strcpy(blz,"70020270");
                  break;
               case 607:
                  strcpy(blz,"74320073");
                  break;
               case 608:
                  strcpy(blz,"72020070");
                  break;
               case 609:
                  strcpy(blz,"72020070");
                  break;
               case 610:
                  strcpy(blz,"72020070");
                  break;
               case 611:
                  strcpy(blz,"72020070");
                  break;
               case 612:
                  strcpy(blz,"71120077");
                  break;
               case 613:
                  strcpy(blz,"70020270");
                  break;
               case 614:
                  strcpy(blz,"72020070");
                  break;
               case 615:
                  strcpy(blz,"70025175");
                  break;
               case 616:
                  strcpy(blz,"73420071");
                  break;
               case 617:
                  strcpy(blz,"68020186");
                  break;
               case 618:
                  strcpy(blz,"73120075");
                  break;
               case 619:
                  strcpy(blz,"60020290");
                  break;
               case 620:
                  strcpy(blz,"71120077");
                  break;
               case 621:
                  strcpy(blz,"71120077");
                  break;
               case 622:
                  strcpy(blz,"74320073");
                  break;
               case 623:
                  strcpy(blz,"72020070");
                  break;
               case 624:
                  strcpy(blz,"71020072");
                  break;
               case 625:
                  strcpy(blz,"71023173");
                  break;
               case 626:
                  strcpy(blz,"71020072");
                  break;
               case 627:
                  strcpy(blz,"71021270");
                  break;
               case 628:
                  strcpy(blz,"71120077");
                  break;
               case 629:
                  strcpy(blz,"73120075");
                  break;
               case 630:
                  strcpy(blz,"71121176");
                  break;
               case 631:
                  strcpy(blz,"71022182");
                  break;
               case 632:
                  strcpy(blz,"70020270");
                  break;
               case 633:
                  strcpy(blz,"74320073");
                  break;
               case 634:
                  strcpy(blz,"70020270");
                  break;
               case 635:
                  strcpy(blz,"70320090");
                  break;
               case 636:
                  strcpy(blz,"70320090");
                  break;
               case 637:
                  strcpy(blz,"72120078");
                  break;
               case 638:
                  strcpy(blz,"72120078");
                  break;
               case 640:
                  strcpy(blz,"70020270");
                  break;
               case 641:
                  strcpy(blz,"70020270");
                  break;
               case 643:
                  strcpy(blz,"74320073");
                  break;
               case 644:
                  strcpy(blz,"70020270");
                  break;
               case 645:
                  strcpy(blz,"70020270");
                  break;
               case 646:
                  strcpy(blz,"70020270");
                  break;
               case 647:
                  strcpy(blz,"70020270");
                  break;
               case 648:
                  strcpy(blz,"72120078");
                  break;
               case 649:
                  strcpy(blz,"72122181");
                  break;
               case 650:
                  strcpy(blz,"54520194");
                  break;
               case 652:
                  strcpy(blz,"71021270");
                  break;
               case 653:
                  strcpy(blz,"70020270");
                  break;
               case 654:
                  strcpy(blz,"70020270");
                  break;
               case 655:
                  strcpy(blz,"72120078");
                  break;
               case 656:
                  strcpy(blz,"71120078");
                  break;
               case 657:
                  strcpy(blz,"71020072");
                  break;
               case 658:
                  strcpy(blz,"68020186");
                  break;
               case 659:
                  strcpy(blz,"54520194");
                  break;
               case 660:
                  strcpy(blz,"54620093");
                  break;
               case 661:
                  strcpy(blz,"74320073");
                  break;
               case 662:
                  strcpy(blz,"73120075");
                  break;
               case 663:
                  strcpy(blz,"70322192");
                  break;
               case 664:
                  strcpy(blz,"72120078");
                  break;
               case 665:
                  strcpy(blz,"70321194");
                  break;
               case 666:
                  strcpy(blz,"73322380");
                  break;
               case 667:
                  strcpy(blz,"60020290");
                  break;
               case 668:
                  strcpy(blz,"60020290");
                  break;
               case 669:
                  strcpy(blz,"73320073");
                  break;
               case 670:
                  strcpy(blz,"75020073");
                  break;
               case 671:
                  strcpy(blz,"74220075");
                  break;
               case 672:
                  strcpy(blz,"74020074");
                  break;
               case 673:
                  strcpy(blz,"74020074");
                  break;
               case 674:
                  strcpy(blz,"74120071");
                  break;
               case 675:
                  strcpy(blz,"74020074");
                  break;
               case 676:
                  strcpy(blz,"74020074");
                  break;
               case 677:
                  strcpy(blz,"72020070");
                  break;
               case 678:
                  strcpy(blz,"72020070");
                  break;
               case 679:
                  strcpy(blz,"54520194");
                  break;
               case 680:
                  strcpy(blz,"71120077");
                  break;
               case 681:
                  strcpy(blz,"67020190");
                  break;
               case 682:
                  strcpy(blz,"78020070");
                  break;
               case 683:
                  strcpy(blz,"71020072");
                  break;
               case 684:
                  strcpy(blz,"70020270");
                  break;
               case 685:
                  strcpy(blz,"70020270");
                  break;
               case 686:
                  strcpy(blz,"70020270");
                  break;
               case 687:
                  strcpy(blz,"70020270");
                  break;
               case 688:
                  strcpy(blz,"70020270");
                  break;
               case 689:
                  strcpy(blz,"70020270");
                  break;
               case 690:
                  strcpy(blz,"76520071");
                  break;
               case 692:
                  strcpy(blz,"70020270");
                  break;
               case 693:
                  strcpy(blz,"73420071");
                  break;
               case 694:
                  strcpy(blz,"70021180");
                  break;
               case 695:
                  strcpy(blz,"70320090");
                  break;
               case 696:
                  strcpy(blz,"74320073");
                  break;
               case 697:
                  strcpy(blz,"54020090");
                  break;
               case 698:
                  strcpy(blz,"73320073");
                  break;
               case 710:
                  strcpy(blz,"30220190");
                  break;
               case 711:
                  strcpy(blz,"70020270");
                  break;
               case 712:
                  strcpy(blz,"10020890");
                  break;
               case 714:
                  strcpy(blz,"76020070");
                  break;
               case 715:
                  strcpy(blz,"75020073");
                  break;
               case 717:
                  strcpy(blz,"74320073");
                  break;
               case 718:
                  strcpy(blz,"87020086");
                  break;
               case 719:
                  strcpy(blz,"37020090");
                  break;
               case 720:
                  strcpy(blz,"30220190");
                  break;
               case 723:
                  strcpy(blz,"77320072");
                  break;
               case 733:
                  strcpy(blz,"83020087");
                  break;
               case 798:
                  strcpy(blz,"70020270");
                  break;
               default:
                  return INVALID_KTO;  /* kein Kontenkreis definiert, dürfte ein ungültiges Konto sein */
                  break;
            }
            b_neu=b8[I blz[0]]+b7[I blz[1]]+b6[I blz[2]]+b5[I blz[3]]+b4[I blz[4]]+b3[I blz[5]]+b2[I blz[6]]+b1[I blz[7]];
            if(b==b_neu)
               ret=OK;
            else
               ret=OK_BLZ_REPLACED;
         }
         else
            ret=OK;

            /* BIC aus der Nachfolge-BLZ bestimmen (die ist hier eingesetzt) */
         *bicp=(const char*)lut_bic_int(blz,0,NULL);
         return ret;


         /* HSH Nordbank AG */
      case 36:

            /* Variante 3: Kontonummernkreise ohne IBAN-Ermittlung */
         if((k1==0 && (k2<=99999 || (k2>=900000 && k2<=29999999) || k2>=60000000))
               ||  k1==9
               || (k1>=20 && k1<=29)
               || (k1>=71 && k1<=84)
               || (k1>=86 && k1<=89))return NO_IBAN_CALCULATION;

         strcpy(blz,"21050000");

            /* Variante 1: 6-stellige Kontonummern, 5. Stelle = 1-8:
             * rechtsbündig mit 3 Nullen aufgefüllt.
             * kto[4]=='9' wurde schon in Variante 3 erledigt
             */
         if(kto[0]=='0' && kto[1]=='0' && kto[2]=='0' && kto[3]=='0' && kto[4]!='0'){
            kto[1]=kto[4];
            kto[2]=kto[5];
            kto[3]=kto[6];
            kto[4]=kto[7];
            kto[5]=kto[8];
            kto[6]=kto[9];
            kto[7]='0';
            kto[8]='0';
            kto[9]='0';
            if((ret=kto_check_blz(blz,kto))<OK)return ret;
            if(b==21050000)
               RETURN_OK_KTO_REPLACED;
            else
               return OK_BLZ_KTO_REPLACED;
         }

            /* Variante 2: alle übrigen Kontonummern:
             * linksbündig aufgefüllt (Standard)
             */
         if((ret=kto_check_blz(blz,kto))<OK)return ret;
         if(b==21050000)
            return OK;
         else
            return OK_BLZ_REPLACED;


         /* The Bank of Tokyo-Mitsubishi UFJ, Ltd. */
      case 37:
         if(b==30010700)return OK;
         strcpy(blz,"30010700");
         *bicp="BOTKDEDXXXX";
         return OK_BLZ_REPLACED;


         /* Ostfriesische Volksbank eG */
      case 38:

         /* drei Sonderfälle angegeben */
         if(b==28590075)return OK;
         switch(b){
            case 26691213:
            case 28591579:
            case 25090300:
               strcpy(blz,"28590075");
               *bicp="GENODEF1LER";
               return OK_BLZ_REPLACED;
            default:
               break;   /* Lumpensammler, Status nicht spezifiziert */
         }
         RETURN_OK;

         /* Oldenburgische Landesbank AG */
      case 39:
         if(b==28020050)return OK;
         strcpy(blz,"28020050");
         *bicp="OLBODEH2XXX";
         return OK_BLZ_REPLACED;


         /* Sparkasse Staufen-Breisach */
      case 40:
         if(b==68052328)return OK;
         strcpy(blz,"68052328");
         *bicp="SOLADES1STF";
         return OK_BLZ_REPLACED;


         /* Bausparkasse Schwäbisch Hall AG */
      case 41:

         /* Bei Bankverbindungen mit der Bankleitzahl 622 200 00 ist generell
          * die IBAN = DE96 5006 0400 0000 0114 04 und der BIC GENODEFFXXX als
          * Ergebnis der Ermittlung zur Verfügung zu stellen.
          *
          * Die angegebene BIC und IBAN ist die Bankverbindung für das Konto der
          * Bausparkasse Schwäbisch Hall AG bei der DZ Bank AG Frankfurt am
          * Main.
          */

         if(b==62220000){
            strcpy(blz,"50060400");
            strcpy(kto,"0000011404");
            *bicp="GENODEFFXXX";
            return OK_BLZ_KTO_REPLACED;
         }
         RETURN_OK;   /* sollte wohl nicht vorkommen, aber zur Sicherheit... */


         /* Deutsche Bundesbank */
      case 42:

            /* nur 8-stellige Konten sind zur IBAN-Berechnung freigegeben */
         if(*kto!='0' || kto[1]!='0')return NO_IBAN_CALCULATION;

            /* Konten ohne IBAN-Berechnung:  nnn 0 0000 bis nnn 0 0999 */
         if(kto[5]=='0' && kto[6]=='0')return NO_IBAN_CALCULATION;

            /* Die Kontonummer muss an der 4. Stelle immer gleich '0' sein.
             *
             * Anm. (MP): die "4." Stelle bezieht sich hier auf die 4. Stelle
             * der 8-stelligen Kontonummer, nicht die der 10-stelligen; daher
             * wird kto[5] auf '0' getestet. Als Beispiel wird 100 0 1000
             * angegeben, wobei die 0 nach initialen 100 damit gemeint ist. Die
             * beiden führenden Nullen werden nicht berücksichtigt.
             */
         if(kto[5]=='0')return OK;

            /* außerdem freigegeben: 50462000 bis 50463999 sowie 50469000 bis 50469999 */
         if(!k1 && ((k2>=50462000 && k2<=50463999) || (k2>=50469000 && k2<=50469999)))return OK;
         return NO_IBAN_CALCULATION;


         /* Sparkasse Pforzheim Calw
          *
          * Die alte BLZ 60651070 verwendet die Prüfziffermethode A9 (diese
          * geht auf die Methoden 06 und 01), um eine sanfte Umstellung der
          * Konten nach der Fusion zu ermöglichen. Die neue BLZ verwendet nur
          * noch die Methode 06. Die Fusion war vor ca. 10 Jahren; Kontonummern
          * die nur nach der Methode A9a gültig sind, sollen nach Aussage der
          * Bank als ungültig betrachtet werden (Anfrage am 24.5.13, Klarstellung
          * ebenfalls in der Email der Bundesbank vom 1.8.13).
          */
      case 43:

         if(b==60651070){
            strcpy(blz,"66650085");
            *bicp="PZHSDE66XXX";
            return OK_BLZ_REPLACED;
         }
         RETURN_OK;


         /* Sparkasse Freiburg */
      case 44:

            /* Sonderkonto */
         if(!k1 && k2==202){
            strcpy(kto,"0002282022");
            RETURN_OK_KTO_REPLACED;
         }
         RETURN_OK;


         /* SEB AG */
      case 45:

            /* Einer nach der Standard IBAN-Regel ermittelten IBAN ist stets
             * der BIC ESSEDE5FXXX zuzuordnen.
             */
         if(version<1){
               *bicp="ESSEDE5FXXX";
               return OK_BLZ_REPLACED;
         }
         else switch(b){   /* Ab Dezember 2013 wird eine Liste von BLZs angegeben */
            case 50210130:
            case 50210131:
            case 50210132:
            case 50210133:
            case 50210134:
            case 50210135:
            case 50210136:
            case 50210137:
            case 50210138:
            case 50210139:
            case 50210140:
            case 50210141:
            case 50210142:
            case 50210143:
            case 50210144:
            case 50210145:
            case 50210146:
            case 50210147:
            case 50210148:
            case 50210149:
            case 50210150:
            case 50210151:
            case 50210152:
            case 50210153:
            case 50210154:
            case 50210155:
            case 50210156:
            case 50210157:
            case 50210158:
            case 50210159:
            case 50210160:
            case 50210161:
            case 50210162:
            case 50210163:
            case 50210164:
            case 50210165:
            case 50210166:
            case 50210167:
            case 50210168:
            case 50210169:
            case 50210170:
            case 50210171:
            case 50210172:
            case 50210173:
            case 50210174:
            case 50210175:
            case 50210176:
            case 50210177:
            case 50210178:
            case 50210179:
            case 50210180:
            case 50210181:
            case 50210182:
            case 50210183:
            case 50210184:
            case 50210185:
            case 50210186:
            case 50210187:
            case 50210188:
            case 50210189:
            case 50510120:
            case 50510121:
            case 50510122:
            case 50510123:
            case 50510124:
            case 50510125:
            case 50510126:
            case 50510127:
            case 50510128:
            case 50510129:
            case 50510130:
            case 50510131:
            case 50510132:
            case 50510133:
            case 50510134:
            case 50510135:
            case 50510136:
            case 50510137:
            case 50510138:
            case 50510139:
            case 50510140:
            case 50510141:
            case 50510142:
            case 50510143:
            case 50510144:
            case 50510145:
            case 50510146:
            case 50510147:
            case 50510148:
            case 50510149:
            case 50510150:
            case 50510151:
            case 50510152:
            case 50510153:
            case 50510154:
            case 50510155:
            case 50510156:
            case 50510157:
            case 50510158:
            case 50510159:
            case 50510160:
            case 50510161:
            case 50510162:
            case 50510163:
            case 50510164:
            case 50510165:
            case 50510166:
            case 50510167:
            case 50510168:
            case 50510169:
            case 50510170:
            case 50510171:
            case 50510172:
            case 50510173:
            case 50510174:
            case 50510175:
            case 50510176:
            case 50510177:
            case 50510178:
            case 50510179:
            case 50510180:
               *bicp="ESSEDE5FXXX";
               return OK_BLZ_REPLACED;
         }
         return OK;


         /* Santander Consumer Bank */
      case 46:

         if(b==31010833)return OK;
         strcpy(blz,"31010833");
         *bicp="CCBADE31XXX";
         return OK_BLZ_REPLACED;


         /* Santander Consumer Bank */
      case 47:

            /* Achtstellige Kontonummern sind rechtsbündig mit Nullen
             * aufzufüllen. Alle anderen Kontonummern mit weniger als zehn
             * Stellen werden nach der Standard-Regel linksbündig mit Nullen
             * aufgefüllt.
             */
         if(*kto=='0' && kto[1]=='0' && kto[2]!='0'){
            for(i=0;i<8;i++)kto[i]=kto[i+2];
            kto[8]=kto[9]='0';
            RETURN_OK_KTO_REPLACED;
         }
         RETURN_OK;

           /* VON ESSEN GmbH & Co. KG Bankgesellschaft */
      case 48:
         if(b==36010200)return OK;
         strcpy(blz,"36010200");
         *bicp="VONEDE33XXX";
         return OK_BLZ_REPLACED;

           /* WGZ Bank */
      case 49:

            /* Sonderkonten */
         if(k1==0)switch(k2){
            case 36:   strcpy(kto,"0002310113"); RETURN_OK_KTO_REPLACED;
            case 936:  strcpy(kto,"0002310113"); RETURN_OK_KTO_REPLACED;
            case 999:  strcpy(kto,"0001310113"); RETURN_OK_KTO_REPLACED;
            case 6060: strcpy(kto,"0000160602"); RETURN_OK_KTO_REPLACED;
            default: break;
         }

            /* Für Kontonummern mit einer '9' an der 5. Stelle muss die Kontonummer, auf deren Ba-
             * sis die IBAN ermittelt wird, abweichend berechnet werden. Die ersten 4 Stellen (inkl.
             * aufgefüllter Nullen) müssen ans Ende gestellt werden, so dass die Kontonummer dann
             * immer mit der '9' anfängt.
             *
             * Diese neu ermittelte Kontonummer hat keine Prüfziffer, die daher auch nicht geprüft
             * werden darf. Ansonsten kann mit dieser Kontonummer die IBAN mit der
             * Standard-IBAN-Regel ermittelt werden.
             */
         if(kto[4]!='9')RETURN_OK;
         memcpy(tmp_buffer,kto,10);
         memcpy(kto,tmp_buffer+4,6);
         memcpy(kto+6,tmp_buffer,4);
         return OK_KTO_REPLACED_NO_PZ;

           /* Sparkasse LeerWittmund */
      case 50:
         if(b==28252760){
            strcpy(blz,"28550000");
            *bicp="BRLADE21LER";
            return OK_BLZ_REPLACED;
         }
         RETURN_OK;


         /* Landesbank Baden-Württemberg / Baden-Württembergische Bank */
      case 51:

            /* Spendenkonten */
         if(k1==0)switch(k2){
            case 333: strcpy(kto,"7832500881"); RETURN_OK_KTO_REPLACED;
            case 502: strcpy(kto,"0001108884"); RETURN_OK_KTO_REPLACED;
            default: break;
         }
         if(k1==5)switch(k2){
            case 500500: strcpy(kto,"0005005000"); RETURN_OK_KTO_REPLACED;
            case 2502502: strcpy(kto,"0001108884"); RETURN_OK_KTO_REPLACED;
            default: break;
         }
         RETURN_OK;

         /* Landesbank Baden-Württemberg / Baden-Württembergische Bank */
      case 52:

            /* Für die Ermittlung der IBAN aus Bankleitzahl und Kontonummer gilt für die Landesbank
             * Baden-Württemberg/BW-Bank die IBAN-Regel 0001 00 (keine IBAN-Berechnung).
             * Ausnahme:
             * Nur für die in der Tabelle aufgeführten Bankleitzahlen/Kontonummer-Kombination ist
             * eine Umrechnung in IBAN und BIC erlaubt.
             * Die nachfolgenden Bankleitzahlen/Snderkontonummern sind vor der Ermittlung der
             * IBAN nach der Standard-IBAN-Regel in die Bankleitzahl neu/echte Kontonummer
             * umzusetzen.
             */

         if(b==67220020 && k1==53 && k2==8810004) {strcpy(blz,"60050101"); strcpy(kto,"0002662604"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==67220020 && k1==53 && k2==8810000) {strcpy(blz,"60050101"); strcpy(kto,"0002659600"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==67020020 && k1==52 && k2==3145700) {strcpy(blz,"60050101"); strcpy(kto,"7496510994"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==69421020 && k1==62 && k2==8908100) {strcpy(blz,"60050101"); strcpy(kto,"7481501341"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==66620020 && k1==48 && k2==40404000){strcpy(blz,"60050101"); strcpy(kto,"7498502663"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==64120030 && k1==12 && k2==1200100) {strcpy(blz,"60050101"); strcpy(kto,"7477501214"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==64020030 && k1==14 && k2==8050100) {strcpy(blz,"60050101"); strcpy(kto,"7469534505"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==63020130 && k1==11 && k2==12156300){strcpy(blz,"60050101"); strcpy(kto,"0004475655"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==62030050 && k1==70 && k2==2703200) {strcpy(blz,"60050101"); strcpy(kto,"7406501175"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         if(b==69220020 && k1==64 && k2==2145400) {strcpy(blz,"60050101"); strcpy(kto,"7485500252"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;}
         return NO_IBAN_CALCULATION;

         /* Landesbank Baden-Württemberg / Baden-Württembergische Bank */
      case 53:

            /* Für die Ermittlung der IBAN aus Bankleitzahl und Kontonummer gilt für die Landesbank
             * Baden-Württemberg/BW-Bank die Standard-IBAN-Regel. Es ist jeweils der BIC der Bankleitzahl
             * laut BLZ-Datei zu verwenden.
             * Abweichend dazu gibt es folgende Besonderheit für Sonderkontonummern:
             * Die nachfolgenden Bankleitzahlen/Sonderkontonummern sind vor der Ermittlung der IBAN
             * nach der Standard-IBAN-Regel in die echte Bankleitzahl neu/ echte Kontonummer umzusetzen.
             */
         switch(b){
            case 55050000:
               if(k1==0)switch(k2){
                  case      901: strcpy(blz,"60050101"); strcpy(kto,"7401507497"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case      902: strcpy(blz,"60050101"); strcpy(kto,"7401507473"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case      908: strcpy(blz,"60050101"); strcpy(kto,"7401507480"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case      910: strcpy(blz,"60050101"); strcpy(kto,"7401507466"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     3500: strcpy(blz,"60050101"); strcpy(kto,"7401555913"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case    35000: strcpy(blz,"60050101"); strcpy(kto,"7401555913"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case    35100: strcpy(blz,"60050101"); strcpy(kto,"7401555913"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case    44000: strcpy(blz,"60050101"); strcpy(kto,"7401555872"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case 55020100: strcpy(blz,"60050101"); strcpy(kto,"7401555872"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  default: break;
               }
               if(k1==1)switch(k2){
                  case 10024270: strcpy(blz,"60050101"); strcpy(kto,"7401501266"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case 10050002: strcpy(blz,"60050101"); strcpy(kto,"7401502234"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case 10132511: strcpy(blz,"60050101"); strcpy(kto,"7401550530"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case 10149226: strcpy(blz,"60050101"); strcpy(kto,"7401512248"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case 19345106: strcpy(blz,"60050101"); strcpy(kto,"7401555906"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  default: break;
               }
               break;

            case 60020030:
               if(k1==10)switch(k2){
                  case   617900: strcpy(blz,"60050101"); strcpy(kto,"0002009906"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case   919900: strcpy(blz,"60050101"); strcpy(kto,"7871531505"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case  2999900: strcpy(blz,"60050101"); strcpy(kto,"0002588991"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case  3340500: strcpy(blz,"60050101"); strcpy(kto,"0002001155"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case  4184600: strcpy(blz,"60050101"); strcpy(kto,"7871513509"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case 40748400: strcpy(blz,"60050101"); strcpy(kto,"0001366705"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case 47444300: strcpy(blz,"60050101"); strcpy(kto,"7871538395"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case 54290000: strcpy(blz,"60050101"); strcpy(kto,"7871521216"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  default: break;
               }
               break;

            case 60050000:
               if(k1==0)switch(k2){
                  case     1523: strcpy(blz,"60050101"); strcpy(kto,"0001364934"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     2502: strcpy(blz,"60050101"); strcpy(kto,"0001366705"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     2535: strcpy(blz,"60050101"); strcpy(kto,"0001119897"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     2811: strcpy(blz,"60050101"); strcpy(kto,"0001367450"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     3002: strcpy(blz,"60050101"); strcpy(kto,"0001367924"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     3009: strcpy(blz,"60050101"); strcpy(kto,"0001367924"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     3080: strcpy(blz,"60050101"); strcpy(kto,"0002009906"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     4596: strcpy(blz,"60050101"); strcpy(kto,"0001372809"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     5500: strcpy(blz,"60050101"); strcpy(kto,"0001375703"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case   123456: strcpy(blz,"60050101"); strcpy(kto,"0001362826"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case   250412: strcpy(blz,"60050101"); strcpy(kto,"7402051588"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case  1029204: strcpy(blz,"60050101"); strcpy(kto,"0002782254"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  default: break;
               }
               break;

            case 66020020:
               if(k1==40)switch(k2){
                  case   604100: strcpy(blz,"60050101"); strcpy(kto,"0002810030"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case  2015800: strcpy(blz,"60050101"); strcpy(kto,"7495530102"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case  2401000: strcpy(blz,"60050101"); strcpy(kto,"7495500967"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case  3746700: strcpy(blz,"60050101"); strcpy(kto,"7495501485"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  default: break;
               }
               break;

            case 66050000:
               if(k1==0)switch(k2){
                  case    85304: strcpy(blz,"60050101"); strcpy(kto,"7402045439"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case    85990: strcpy(blz,"60050101"); strcpy(kto,"7402051588"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case    86345: strcpy(blz,"60050101"); strcpy(kto,"7402046641"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case    86567: strcpy(blz,"60050101"); strcpy(kto,"0001364934"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  default: break;
               }
               break;

            case 86050000:
               if(k1==0)switch(k2){
                  case     1016: strcpy(blz,"60050101"); strcpy(kto,"7461500128"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     2020: strcpy(blz,"60050101"); strcpy(kto,"7461500018"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     3535: strcpy(blz,"60050101"); strcpy(kto,"7461505611"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  case     4394: strcpy(blz,"60050101"); strcpy(kto,"7461505714"); *bicp="SOLADEST600"; return OK_BLZ_KTO_REPLACED;
                  default: break;
               }
               break;
         }
         RETURN_OK;

         /* Evangelische Darlehnsgenossenschaft eG */
      case 54:

            /* Spendenkonten */
         if(k1==0)switch(k2){
            case        500: strcpy(kto,"0000500500"); RETURN_OK_KTO_REPLACED;
            case        502: strcpy(kto,"0000502502"); RETURN_OK_KTO_REPLACED;
            case      18067: strcpy(kto,"0000180670"); RETURN_OK_KTO_REPLACED;
            case     484848: strcpy(kto,"0000484849"); RETURN_OK_KTO_REPLACED;
            case     636306: strcpy(kto,"0000063606"); RETURN_OK_KTO_REPLACED;
            case     760440: strcpy(kto,"0000160440"); RETURN_OK_KTO_REPLACED;
            case    1018413: strcpy(kto,"0010108413"); RETURN_OK_KTO_REPLACED;
            case    2601577: strcpy(kto,"0026015776"); RETURN_OK_KTO_REPLACED;
            case    5005000: strcpy(kto,"0000500500"); RETURN_OK_KTO_REPLACED;
            case   10796740: strcpy(kto,"0010796743"); RETURN_OK_KTO_REPLACED;
            case   11796740: strcpy(kto,"0011796743"); RETURN_OK_KTO_REPLACED;
            case   12796740: strcpy(kto,"0012796743"); RETURN_OK_KTO_REPLACED;
            case   13796740: strcpy(kto,"0013796743"); RETURN_OK_KTO_REPLACED;
            case   14796740: strcpy(kto,"0014796743"); RETURN_OK_KTO_REPLACED;
            case   15796740: strcpy(kto,"0015796743"); RETURN_OK_KTO_REPLACED;
            case   16307000: strcpy(kto,"0163107000"); RETURN_OK_KTO_REPLACED;
            case   16610700: strcpy(kto,"0166107000"); RETURN_OK_KTO_REPLACED;
            case   16796740: strcpy(kto,"0016796743"); RETURN_OK_KTO_REPLACED;
            case   17796740: strcpy(kto,"0017796743"); RETURN_OK_KTO_REPLACED;
            case   18796740: strcpy(kto,"0018796743"); RETURN_OK_KTO_REPLACED;
            case   19796740: strcpy(kto,"0019796743"); RETURN_OK_KTO_REPLACED;
            case   20796740: strcpy(kto,"0020796743"); RETURN_OK_KTO_REPLACED;
            case   21796740: strcpy(kto,"0021796743"); RETURN_OK_KTO_REPLACED;
            case   22796740: strcpy(kto,"0022796743"); RETURN_OK_KTO_REPLACED;
            case   23796740: strcpy(kto,"0023796743"); RETURN_OK_KTO_REPLACED;
            case   24796740: strcpy(kto,"0024796743"); RETURN_OK_KTO_REPLACED;
            case   25796740: strcpy(kto,"0025796743"); RETURN_OK_KTO_REPLACED;
            case   26610700: strcpy(kto,"0266107000"); RETURN_OK_KTO_REPLACED;
            case   26796740: strcpy(kto,"0026796743"); RETURN_OK_KTO_REPLACED;
            case   27796740: strcpy(kto,"0027796743"); RETURN_OK_KTO_REPLACED;
            case   28796740: strcpy(kto,"0028796743"); RETURN_OK_KTO_REPLACED;
            case   29796740: strcpy(kto,"0029796743"); RETURN_OK_KTO_REPLACED;
            case   45796740: strcpy(kto,"0045796743"); RETURN_OK_KTO_REPLACED;
            case   50796740: strcpy(kto,"0050796743"); RETURN_OK_KTO_REPLACED;
            case   51796740: strcpy(kto,"0051796743"); RETURN_OK_KTO_REPLACED;
            case   52796740: strcpy(kto,"0052796743"); RETURN_OK_KTO_REPLACED;
            case   53796740: strcpy(kto,"0053796743"); RETURN_OK_KTO_REPLACED;
            case   54796740: strcpy(kto,"0054796743"); RETURN_OK_KTO_REPLACED;
            case   55796740: strcpy(kto,"0055796743"); RETURN_OK_KTO_REPLACED;
            case   56796740: strcpy(kto,"0056796743"); RETURN_OK_KTO_REPLACED;
            case   57796740: strcpy(kto,"0057796743"); RETURN_OK_KTO_REPLACED;
            case   58796740: strcpy(kto,"0058796743"); RETURN_OK_KTO_REPLACED;
            case   59796740: strcpy(kto,"0059796743"); RETURN_OK_KTO_REPLACED;
            case   60796740: strcpy(kto,"0060796743"); RETURN_OK_KTO_REPLACED;
            case   61796740: strcpy(kto,"0061796743"); RETURN_OK_KTO_REPLACED;
            case   62796740: strcpy(kto,"0062796743"); RETURN_OK_KTO_REPLACED;
            case   63796740: strcpy(kto,"0063796743"); RETURN_OK_KTO_REPLACED;
            case   64796740: strcpy(kto,"0064796743"); RETURN_OK_KTO_REPLACED;
            case   65796740: strcpy(kto,"0065796743"); RETURN_OK_KTO_REPLACED;
            case   66796740: strcpy(kto,"0066796743"); RETURN_OK_KTO_REPLACED;
            case   67796740: strcpy(kto,"0067796743"); RETURN_OK_KTO_REPLACED;
            case   68796740: strcpy(kto,"0068796743"); RETURN_OK_KTO_REPLACED;
            case   69796740: strcpy(kto,"0069796743"); RETURN_OK_KTO_REPLACED;
            default: break;
         }
         else if(k1==17 && k2==61070000){strcpy(kto,"0176107000"); RETURN_OK_KTO_REPLACED;}
         else if(k1==22 && k2==10531180){strcpy(kto,"0201053180"); RETURN_OK_KTO_REPLACED;}

         if(version>0){    /* gültig ab 3.3.2014 */
            if(k1==0)switch(k2){
               case   624044: return OK_IBAN_WITHOUT_KC_TEST;
               case  4063060: return OK_IBAN_WITHOUT_KC_TEST;
               case 20111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 20211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 20311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 20411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 20511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 20611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 20711908: return OK_IBAN_WITHOUT_KC_TEST;
               case 20811908: return OK_IBAN_WITHOUT_KC_TEST;
               case 20911908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21711908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21811908: return OK_IBAN_WITHOUT_KC_TEST;
               case 21911908: return OK_IBAN_WITHOUT_KC_TEST;
               case 22111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 22211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 22311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 22411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 22511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 22611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 46211991: return OK_IBAN_WITHOUT_KC_TEST;
               case 50111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 50211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 50311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 50411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 50511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 50611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 50711908: return OK_IBAN_WITHOUT_KC_TEST;
               case 50811908: return OK_IBAN_WITHOUT_KC_TEST;
               case 50911908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51111991: return OK_IBAN_WITHOUT_KC_TEST;
               case 51211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51211991: return OK_IBAN_WITHOUT_KC_TEST;
               case 51311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51711908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51811908: return OK_IBAN_WITHOUT_KC_TEST;
               case 51911908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52111991: return OK_IBAN_WITHOUT_KC_TEST;
               case 52211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52211991: return OK_IBAN_WITHOUT_KC_TEST;
               case 52311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52711908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52811908: return OK_IBAN_WITHOUT_KC_TEST;
               case 52911908: return OK_IBAN_WITHOUT_KC_TEST;
               case 53111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 53211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 53311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 57111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 58111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 58211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 58311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 58411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 58511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80711908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80811908: return OK_IBAN_WITHOUT_KC_TEST;
               case 80911908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81711908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81811908: return OK_IBAN_WITHOUT_KC_TEST;
               case 81911908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82111908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82211908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82311908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82411908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82511908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82611908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82711908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82811908: return OK_IBAN_WITHOUT_KC_TEST;
               case 82911908: return OK_IBAN_WITHOUT_KC_TEST;
               case 99624044: return OK_IBAN_WITHOUT_KC_TEST;
            }
            else
               if(k1==3 && k2==143869)return OK_IBAN_WITHOUT_KC_TEST;
         }
         RETURN_OK;

         /* BHW Kreditservice GmbH */
      case 55:
         if(b!=25410200){
            strcpy(blz,"25410200");
            *bicp="BHWBDE2HXXX";
            return OK_BLZ_REPLACED;
         }
         RETURN_OK;

         /* SEB AG */
      case 56:
            /* Spendenkonten: nur mit festgelegten IBANs -> Konto und evl. BLZ/BIC anpassen */
         if(k1==0)switch(k2){
            case       36: strcpy(kto,"1010240003"); if(b!=38010111){strcpy(blz,"38010111"); *bicp="ESSEDE5F380"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case       50: strcpy(kto,"1328506100"); if(b!=48010111){strcpy(blz,"48010111"); *bicp="ESSEDE5F480"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case       99: strcpy(kto,"1826063000"); if(b!=43010111){strcpy(blz,"43010111"); *bicp="ESSEDE5F430"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      110: strcpy(kto,"1015597802"); if(b!=25010111){strcpy(blz,"25010111"); *bicp="ESSEDE5F250"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      240: strcpy(kto,"1010240000"); if(b!=38010111){strcpy(blz,"38010111"); *bicp="ESSEDE5F380"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      333: strcpy(kto,"1011296100"); if(b!=38010111){strcpy(blz,"38010111"); *bicp="ESSEDE5F380"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      555: strcpy(kto,"1600220800"); if(b!=10010111){strcpy(blz,"10010111"); *bicp="ESSEDE5F100"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      556: strcpy(kto,"1000556100"); if(b!=39010111){strcpy(blz,"39010111"); *bicp="ESSEDE5F390"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      606: strcpy(kto,"1967153801"); if(b!=25010111){strcpy(blz,"25010111"); *bicp="ESSEDE5F250"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      700: strcpy(kto,"1070088000"); if(b!=26510111){strcpy(blz,"26510111"); *bicp="ESSEDE5F265"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      777: strcpy(kto,"1006015200"); if(b!=25010111){strcpy(blz,"25010111"); *bicp="ESSEDE5F250"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case      999: strcpy(kto,"1010240001"); if(b!=38010111){strcpy(blz,"38010111"); *bicp="ESSEDE5F380"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     1234: strcpy(kto,"1369152400"); if(b!=25010111){strcpy(blz,"25010111"); *bicp="ESSEDE5F250"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     1313: strcpy(kto,"1017500000"); if(b!=57010111){strcpy(blz,"57010111"); *bicp="ESSEDE5F570"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     1888: strcpy(kto,"1241113000"); if(b!=37010111){strcpy(blz,"37010111"); *bicp="ESSEDE5F370"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     1953: strcpy(kto,"1026500901"); if(b!=25010111){strcpy(blz,"25010111"); *bicp="ESSEDE5F250"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     1998: strcpy(kto,"1547620500"); if(b!=67010111){strcpy(blz,"67010111"); *bicp="ESSEDE5F670"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     2007: strcpy(kto,"1026500907"); if(b!=25010111){strcpy(blz,"25010111"); *bicp="ESSEDE5F250"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     4004: strcpy(kto,"1635100100"); if(b!=37010111){strcpy(blz,"37010111"); *bicp="ESSEDE5F370"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     4444: strcpy(kto,"1304610900"); if(b!=67010111){strcpy(blz,"67010111"); *bicp="ESSEDE5F670"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     5000: strcpy(kto,"1395676000"); if(b!=25010111){strcpy(blz,"25010111"); *bicp="ESSEDE5F250"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     5510: strcpy(kto,"1611754300"); if(b!=29010111){strcpy(blz,"29010111"); *bicp="ESSEDE5F290"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     6060: strcpy(kto,"1000400200"); if(b!=50010111){strcpy(blz,"50010111"); *bicp="ESSEDE5FXXX"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case     6800: strcpy(kto,"1296401301"); if(b!=67010111){strcpy(blz,"67010111"); *bicp="ESSEDE5F670"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case    55555: strcpy(kto,"1027758200"); if(b!=38010111){strcpy(blz,"38010111"); *bicp="ESSEDE5F380"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case    60000: strcpy(kto,"1005007001"); if(b!=50010111){strcpy(blz,"50010111"); *bicp="ESSEDE5FXXX"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case    66666: strcpy(kto,"1299807801"); if(b!=20010111){strcpy(blz,"20010111"); *bicp="ESSEDE5F200"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case   102030: strcpy(kto,"1837501600"); if(b!=37010111){strcpy(blz,"37010111"); *bicp="ESSEDE5F370"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case   121212: strcpy(kto,"1249461502"); if(b!=70010111){strcpy(blz,"70010111"); *bicp="ESSEDE5F700"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case   130500: strcpy(kto,"1413482100"); if(b!=30010111){strcpy(blz,"30010111"); *bicp="ESSEDE5F300"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case   202020: strcpy(kto,"1213431002"); if(b!=37010111){strcpy(blz,"37010111"); *bicp="ESSEDE5F370"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case   414141: strcpy(kto,"1010555101"); if(b!=38010111){strcpy(blz,"38010111"); *bicp="ESSEDE5F380"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case   666666: strcpy(kto,"1798758900"); if(b!=20010111){strcpy(blz,"20010111"); *bicp="ESSEDE5F200"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
            case  5000000: strcpy(kto,"1403124100"); if(b!=37010111){strcpy(blz,"37010111"); *bicp="ESSEDE5F370"; return OK_BLZ_KTO_REPLACED;} else return OK_KTO_REPLACED;
         }
         else if(k1==5 && k2==500500){
            strcpy(kto,"1045720000");
            if(b!=60010111){
               strcpy(blz,"60010111");
               *bicp="ESSEDE5F600";
               return OK_BLZ_KTO_REPLACED;
            }
            else
               return OK_KTO_REPLACED;
         }

            /* für die folgenden BLZs sind nur zehnstelllige Kontonummern erlaubt: */
         switch(b){
            case 10010111:
            case 13010111:
            case 16010111:
            case 20010111:
            case 21010111:
            case 21210111:
            case 23010111:
            case 25010111:
            case 25410111:
            case 25910111:
            case 26010111:
            case 26510111:
            case 27010111:
            case 28010111:
            case 29010111:
            case 29210111:
            case 30010111:
            case 31010111:
            case 33010111:
            case 35010111:
            case 35211012:
            case 36010111:
            case 36210111:
            case 37010111:
            case 38010111:
            case 39010111:
            case 40010111:
            case 41010111:
            case 42010111:
            case 42610112:
            case 43010111:
            case 44010111:
            case 46010111:
            case 48010111:
            case 50010111:
            case 50510111:
            case 51010111:
            case 51310111:
            case 51410111:
            case 52010111:
            case 54210111:
            case 55010111:
            case 57010111:
            case 58510111:
            case 59010111:
            case 60010111:
            case 63010111:
            case 65310111:
            case 66010111:
            case 66610111:
            case 67010111:
            case 67210111:
            case 68010111:
            case 68310111:
            case 69010111:
            case 70010111:
            case 72010111:
            case 75010111:
            case 76010111:
            case 79010111:
            case 79510111:
            case 81010111:
            case 82010111:
            case 86010111:
               if(k1<10)return INVALID_KTO;
            default:
               break;
         }
         RETURN_OK;

         /* Badenia Bausparkasse */
      case 57:
         if(b!=66010200){
            strcpy(blz,"66010200");
            *bicp="BBSPDE6KXXX";
            return OK_BLZ_REPLACED;
         }
         RETURN_OK;


         /* Lumpensammler für unbekannte Regeln */
      default: 
         return IBAN_RULE_UNKNOWN;
   }
}
#endif

/* Funktion lut_multiple() +§§§2 */
/* ###########################################################################
 * # lut_multiple(): Universalfunktion, um zu einer gegebenen Bankleitzahl   #
 * # mehrere Werte der LUT-Datei zu bestimmen. Die gewünschten Variablen     #
 * # werden der Funktion als Referenz übergeben; die Funktion schreibt dann  #
 * # die Anfangsadresse im zugehörigen internen Array in die übergebenen     #
 * # Variablen (müssen ebenfalls Arraypointer sein!), und übergibt in der    #
 * # Variablen cnt noch die Anzahl der Zweigstellen.                         #
 * #                                                                         #
 * # Falls für die Bankleitzahl NULL oder ein Leerstring angegeben wird,     #
 * # werden die Anfangsadressen der interenen Arrays und als Anzahl (cnt)    #
 * # die Anzahl der Hauptstellen zurückgegeben. Die Anzahl aller Werte       #
 * # findet sich in der Variablen cnt_all (vorletzte Variable); das Array    #
 * # mit den Indizes der Hauptstellen wird in der letzten Variable zurück-   #
 * # gegeben (start_idx).                                                    #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

#define SET_NULL if(cnt)*cnt=0; if(p_blz)*p_blz=NULL; if(p_name)*p_name=NULL; \
      if(p_name_kurz)*p_name_kurz=NULL; if(p_plz)*p_plz=NULL; if(p_ort)*p_ort=NULL; \
      if(p_pan)*p_pan=NULL; if(p_bic)*p_bic=NULL; if(p_pz)*p_pz=-1; if(p_nr)*p_nr=NULL; \
      if(p_aenderung)*p_aenderung=NULL; if(p_loeschung)*p_loeschung=NULL; \
      if(p_nachfolge_blz)*p_nachfolge_blz=NULL; if(id)*id=0; if(cnt_all)*cnt_all=0; \
      if(start_idx)*start_idx=NULL

DLL_EXPORT int lut_multiple(char *b,int *cnt,int **p_blz,char  ***p_name,char ***p_name_kurz,
      int **p_plz,char ***p_ort,int **p_pan,char ***p_bic,int *p_pz,int **p_nr,
      char **p_aenderung,char **p_loeschung,int **p_nachfolge_blz,int *id,
      int *cnt_all,int **start_idx)
{
   int idx;

   if(init_status<7){
      SET_NULL;
      RETURN(LUT2_NOT_INITIALIZED);   /* Bankleitzahlen noch nicht initialisiert */
   }
   if(cnt_all)*cnt_all=lut2_cnt;
   if(start_idx)*start_idx=startidx;

        /* falls für die BLZ NULL oder ein Leerstring übergeben wurde, Anfangsadressen
         * und Gesamtgröße der Arrays zurückliefern.
         */
   if(!b || !*b){
      idx=0;
      if(cnt)*cnt=lut2_cnt_hs;
   }
   else{
      if((idx=lut_index(b))<0){  /* ungültige BLZ */
         SET_NULL;
         return idx;
      }
      if(cnt){
         if(!filialen)  /* nur Hauptstellen in der Datei */
            *cnt=1;
         else
            *cnt=filialen[idx];
      }
   }
   return lut_multiple_int(idx,cnt,p_blz,p_name,p_name_kurz,p_plz,p_ort,p_pan,p_bic,p_pz,
         p_nr,p_aenderung,p_loeschung,p_nachfolge_blz,id,cnt_all,start_idx);
}

DLL_EXPORT int lut_multiple_i(int b,int *cnt,int **p_blz,char  ***p_name,char ***p_name_kurz,
      int **p_plz,char ***p_ort,int **p_pan,char ***p_bic,int *p_pz,int **p_nr,
      char **p_aenderung,char **p_loeschung,int **p_nachfolge_blz,int *id,
      int *cnt_all,int **start_idx)
{
   int idx;

   if(init_status<7){
      SET_NULL;
      RETURN(LUT2_NOT_INITIALIZED);   /* Bankleitzahlen noch nicht initialisiert */
   }
   if(cnt_all)*cnt_all=lut2_cnt;
   if(start_idx)*start_idx=startidx;

        /* falls für die BLZ NULL oder ein Leerstring übergeben wurde, Anfangsadressen
         * und Gesamtgröße der Arrays zurückliefern.
         */
   if(!b){
      idx=0;
      if(cnt)*cnt=lut2_cnt_hs;
   }
   else{
      if((idx=lut_index_i(b))<0){  /* ungültige BLZ */
         SET_NULL;
         return idx;
      }
      if(cnt){
         if(!filialen)  /* nur Hauptstellen in der Datei */
            *cnt=1;
         else
            *cnt=filialen[idx];
      }
   }
   return lut_multiple_int(idx,cnt,p_blz,p_name,p_name_kurz,p_plz,p_ort,p_pan,p_bic,p_pz,
         p_nr,p_aenderung,p_loeschung,p_nachfolge_blz,id,cnt_all,start_idx);
}

static int lut_multiple_int(int idx,int *cnt,int **p_blz,char  ***p_name,char ***p_name_kurz,
      int **p_plz,char ***p_ort,int **p_pan,char ***p_bic,int *p_pz,int **p_nr,
      char **p_aenderung,char **p_loeschung,int **p_nachfolge_blz,int *id,
      int *cnt_all,int **start_idx)
{
   int start,retval=OK;

   start=startidx[idx];
   if(id)*id=idx;

   if(p_blz){
      if(!blz){
         *p_blz=leer_zahl;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_blz=blz+start;
   }

   if(p_name){
      if(!name){
         *p_name=leer_string;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_name=name+start;
   }

   if(p_name_kurz){
      if(!name_kurz){
         *p_name_kurz=leer_string;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_name_kurz=name_kurz+start;
   }

   if(p_plz){
      if(!plz){
         *p_plz=leer_zahl;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_plz=plz+start;
   }

   if(p_ort){
      if(!ort){
         *p_ort=leer_string;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_ort=ort+start;
   }

   if(p_pan){
      if(!pan){
         *p_pan=leer_zahl;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_pan=pan+start;
   }

   if(p_bic){
      if(!bic){
         *p_bic=leer_string;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_bic=bic+start;
   }

   if(p_pz){
      if(!pz_methoden){
         *p_pz=-1;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_pz=pz_methoden[idx];    /* PZ-Methoden werden nicht für die Filialen gespeichert, daher idx */
   }

   if(p_nr){
      if(!bank_nr){
         *p_nr=leer_zahl;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_nr=bank_nr+start;
   }

   if(p_aenderung){
      if(!aenderung){
         *p_aenderung=leer_char;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_aenderung=aenderung+start;
   }

   if(p_loeschung){
      if(!loeschung){
         *p_loeschung=leer_char;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_loeschung=loeschung+start;
   }

   if(p_nachfolge_blz){
      if(!nachfolge_blz){
         *p_nachfolge_blz=leer_zahl;
         retval=LUT2_PARTIAL_OK;
      }
      else
         *p_nachfolge_blz=nachfolge_blz+start;
   }
   RETURN(retval);
}

/* Funktion lut_cleanup() +§§§1 */
/* ###########################################################################
 * # lut_cleanup(): Aufräuarbeiten                                           #
 * # Die Funktion lut_cleanup() gibt allen belegten Speicher frei und setzt  #
 * # die entsprechenden Variablen auf NULL.                                  #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int lut_cleanup(void)
{
   int i;

   INITIALIZE_WAIT;     /* zunächst testen, ob noch eine andere Initialisierung läuft (z.B. in einem anderen Thread) */
   init_in_progress=1;  /* Lockflag für Tests und Initialierung setzen */
   init_status|=16;     /* init_status wird bei der Prüfung getestet */
   *lut_id=0;
   lut_id_status=0;
   lut_blocks_missing=0;
   extra_init_done=0;
   lut_init_level=current_lut_level=current_lut_set=-1;
   if(init_status&8)INITIALIZE_WAIT;

      /* falls kto_check_init() den Notausstieg mit INIT_FATAL_ERROR gemacht
       * hatte, wurde init_in_progress auf 0 gesetzt; jetzt wieder setzen.
       */
   init_in_progress=1;
   if(blz_f && startidx[lut2_cnt_hs-1]==lut2_cnt_hs-1)
      pz_f=blz_f=NULL; /* kein eigenes Array */
   else{
      FREE(blz_f);
      FREE(pz_f);
   }
   FREE(zweigstelle_f);
   FREE(zweigstelle_f1);
   FREE(sort_bic_h);
   FREE(bic_h);
   FREE(sort_bic);
   FREE(sort_name);
   FREE(sort_name_kurz);
   FREE(sort_ort);
   FREE(sort_blz);
   FREE(sort_pz_f);
   FREE(sort_plz);
   FREE(sort_iban_regel);
   if(name_raw && name_data!=name_raw)
      FREE(name_raw);
   else
      name_raw=NULL;
   if(name_kurz_raw && name_kurz_data!=name_kurz_raw)
      FREE(name_kurz_raw);
   else
      name_kurz_raw=NULL;
   if(name_name_kurz_raw && name_name_kurz_data!=name_name_kurz_raw)
      FREE(name_name_kurz_raw);
   else
      name_name_kurz_raw=NULL;
   if(ort_raw && ort_data!=ort_raw)
      FREE(ort_raw);
   else
      ort_raw=NULL;
   FREE(name);
   FREE(name_data);
   FREE(name_kurz);
   FREE(name_kurz_data);
   FREE(name_name_kurz_data);
   FREE(ort);
   FREE(ort_data);
   FREE(bic);
   FREE(bic_buffer);
   FREE(aenderung);
   FREE(loeschung);
   FREE(blz);
   FREE(startidx);
   FREE(startidx_r);
   FREE(hs_idx);
   FREE(plz);
   FREE(filialen);
   FREE(pan);
   FREE(pz_methoden);
   FREE(bank_nr);
   FREE(nachfolge_blz);
   FREE(current_info);
   FREE(own_buffer);
   FREE(hash);
   FREE(default_buffer);
   FREE(own_iban);
   FREE(iban_regel);
   FREE(current_lutfile);
   FREE(volltext);
   FREE(volltext_banken);
   FREE(volltext_data);
   FREE(volltext_start);
   FREE(sort_volltext);
   FREE(sort_blz);
   for(i=0;i<400;i++)lut2_block_status[i]=0;
   for(i=0;i<last_lut_suche_idx;i++)lut_suche_free(i);
   FREE(lut_suche_arr);
   last_lut_suche_idx=0;
   if(handle_ptr){
      for(i=0;i<h_cnt;i++)if(handle_ptr[i] && handle_free[i])FREE(handle_ptr[i]);
      free(handle_ptr);
   }

   if(init_status&8){

         /* bei init_status&8 ist wohl eine Initialisierung dazwischengekommen (sollte
          * eigentlich nicht passieren); daher nur eine Fehlermeldung zurückgeben.
          */
      usleep(50000); /* etwas abwarten */
      lut_cleanup(); /* neuer Versuch, aufzuräumen */
      RETURN(INIT_FATAL_ERROR);
   }
   init_status&=1;
   init_in_progress=0;
   return OK;
}

/* Funktion generate_lut() +§§§1 */
/* ###########################################################################
 * # Die Funktion generate_lut() generiert aus der BLZ-Datei der deutschen   #
 * # Bundesbank (knapp 4 MB) eine kleine Datei (ca. 14 KB), in der nur die   #
 * # Bankleitzahlen und Prüfziffermethoden gespeichert sind. Um die Datei    #
 * # klein zu halten, werden normalerweise nur Differenzen zur Vorgänger-BLZ #
 * # gespeichert (meist mit 1 oder 2 Byte); die Prüfziffermethode wird in    #
 * # einem Byte kodiert. Diese kleine Datei läßt sich dann natürlich viel    #
 * # schneller einlesen als die große Bundesbank-Datei.                      #
 * #                                                                         #
 * # Ab Version 3 wird für die Funktionalität die Routine generate_lut2()    #
 * # (mit Defaultwerten für Felder und Slots) benutzt.                       #
 * #                                                                         #
 * # Bugs: es wird für eine BLZ nur eine Prüfziffermethode unterstützt.      #
 * #      (nach Bankfusionen finden sich für eine Bank manchmal zwei         #
 * #      Prüfziffermethoden; das Problem wird mit dem neuen Dateiformat     #
 * #      noch einmal angegangen.                                            #
 * #                                                                         #
 * # Copyright (C) 2002-2005 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

DLL_EXPORT int generate_lut_t(char *inputname,char *outputname,char *user_info,int lut_version,KTO_CHK_CTX *ctx)
{
   return generate_lut2_p(inputname,outputname,user_info,NULL,9,1,0,lut_version,0);
}

DLL_EXPORT int generate_lut(char *inputname,char *outputname,char *user_info,int lut_version)
{
   return generate_lut2_p(inputname,outputname,user_info,NULL,9,1,0,lut_version,0);
}

/* Funktion read_lut() +§§§1 */
/* ###########################################################################
 * # Die Funktion read_lut() liest die Lookup-Tabelle mit Bankleitzahlen und #
 * # Prüfziffermethoden im alten Format (1.0/1.1) ein und führt einige       #
 * # Konsistenz-Tests durch.                                                 #
 * #                                                                         #
 * # Bugs: für eine BLZ wird nur eine Prüfziffermethode unterstützt (s.o.).  #
 * #                                                                         #
 * # Copyright (C) 2002-2005 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

static int read_lut(char *filename,int *cnt_blz)
{
   unsigned char *inbuffer,*uptr;
   int b,h,k,i,j,prev,cnt,lut_version;
   UINT4 adler1,adler2;
   struct stat s_buf;
   int in;

   if(cnt_blz)*cnt_blz=0;
   if(!(init_status&1))init_atoi_table();
   if(stat(filename,&s_buf)==-1)RETURN(NO_LUT_FILE);
   if(!(inbuffer=(unsigned char *)calloc(s_buf.st_size+128,1)))RETURN(ERROR_MALLOC);
   if((in=open(filename,O_RDONLY|O_BINARY))<0)RETURN(NO_LUT_FILE);
   if(!(cnt=read(in,inbuffer,s_buf.st_size)))RETURN(FILE_READ_ERROR);
   close(in);
   lut_version= -1;
   if(!strncmp((char *)inbuffer,"BLZ Lookup Table/Format 1.0\n",28))
      lut_version=1;
   if(!strncmp((char *)inbuffer,"BLZ Lookup Table/Format 1.1\n",28))
      lut_version=2;
   if(lut_version==-1)RETURN(INVALID_LUT_FILE);
   for(uptr=inbuffer,i=cnt;*uptr++!='\n';i--);  /* Signatur */
   if(lut_version==2){  /* Info-Zeile überspringen */
      for(i--,j=0;*uptr++!='\n';i--);
      if(*(uptr-2)=='\\')for(i--;*uptr++!='\n';i--); /* user_info */
   }
   i-=9;
   READ_LONG(cnt);
   READ_LONG(adler1);
   adler2=adler32a(0,(char *)uptr,i)^cnt;
   if(adler1!=adler2)RETURN(LUT_CRC_ERROR);
   if(cnt>(i-8)/2)RETURN(INVALID_LUT_FILE);

      /* zunächst u.U. Speicher freigeben, damit keine Lecks entstehen */
   FREE(blz);
   FREE(startidx);
   FREE(startidx_r);
   FREE(hs_idx);
   FREE(hash);
   FREE(pz_methoden);
   if(!(blz=(int *)calloc(j=cnt+100,sizeof(int))) || !(startidx=(int *)calloc(j,sizeof(int)))
         || !(hash=(short int *)calloc(HASH_BUFFER_SIZE,sizeof(short))) || !(pz_methoden=(int *)calloc(j,sizeof(int)))){
      lut_cleanup();
      RETURN(ERROR_MALLOC);
   }

   for(j=prev=i=0;i<cnt;uptr++){
      if(*uptr<251){   /* 1 Byte Differenz, positiv */
         blz[i]=prev+*uptr;
         prev=blz[i];
         pz_methoden[i++]=*++uptr;
      }
      else switch(*uptr){
         case 251:   /* 2 Byte Differenz, negativ */
            uptr++;
            blz[i]= prev-(*uptr+(*(uptr+1)<<8));
            uptr+=2;
            prev=blz[i];
            pz_methoden[i++]=*uptr;
            break;
         case 252:   /* 1 Byte Differenz, negativ */
            uptr++;
            blz[i]= prev-*uptr;
            prev=blz[i];
            pz_methoden[i++]=*++uptr;
            break;
         case 253:   /* 4 Byte Wert der BLZ komplett, nicht Differenz */
            uptr++;
            blz[i]= *uptr+(*(uptr+1)<<8)+(*(uptr+2)<<16)+(*(uptr+3)<<24);
            uptr+=4;
            prev=blz[i];
            pz_methoden[i++]=*uptr;
            break;
         case 254:   /* 2 Byte Differenz, positiv */
            uptr++;
            blz[i]=prev+*uptr+(*(uptr+1)<<8);
            uptr+=2;
            prev=blz[i];
            pz_methoden[i++]=*uptr;
            break;
         case 255:   /* reserviert */
            RETURN(INVALID_LUT_FILE);
      }
   }
   blz[cnt]=BLZ_FEHLER;
   for(;i<cnt+5;i++)blz[i]=BLZ_FEHLER+i;
   for(i=0;i<HASH_BUFFER_SIZE;i++)hash[i]=cnt;
   for(i=0;i<cnt;i++){
      b=blz[i];      /* b BLZ, h Hashwert */
      k=b%10; h= hx8[k]; b/=10;
      k=b%10; h+=hx7[k]; b/=10;
      k=b%10; h+=hx6[k]; b/=10;
      k=b%10; h+=hx5[k]; b/=10;
      k=b%10; h+=hx4[k]; b/=10;
      k=b%10; h+=hx3[k]; b/=10;
      k=b%10; h+=hx2[k]; b/=10;
      k=b%10; h+=hx1[k];
      while(hash[h]!=cnt)h++;
      hash[h]=i;
   }
   FREE(inbuffer);
   if(cnt_blz)*cnt_blz=cnt;
   return OK;
}

/* Funktion init_atoi_table() +§§§1 */
/* ###########################################################################
 * # Die Funktion init_atoi_table initialisiert die Arrays b1 bis b8, die    #
 * # zur schnellen Umwandlung des Bankleitzahlstrings in eine Zahl dienen.   #
 * # Dazu werden 8 Arrays aufgebaut (für jede Stelle eines); die Umwandlung  #
 * # von String nach int läßt sich damit auf Arrayoperationen und Summierung #
 * # zurückführen, was wesentlich schneller ist, als die sonst nötigen acht  #
 * # Multiplikationen mit dem jeweiligen Stellenwert.                        #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static void init_atoi_table(void)
{
   int i,ziffer;
   unsigned long l;

#if 1
      /* Änderungen zum 9.6.2014 aktivieren */
   if(time(NULL)>1410127200)pz_aenderungen_aktivieren=1;
#endif

   /* ungültige Ziffern; Blanks und Tabs werden ebenfalls als ungültig
    * angesehen(!), da die Stellenzuordnung sonst nicht mehr stimmt. Ausnahme:
    * Am Ende ist ein Blank erlaubt; die BLZ wird damit als abgeschlossen
    * angesehen.
    */
   for(i=0;i<256;i++){
      b0[i]=b1[i]=b2[i]=b3[i]=b4[i]=b5[i]=b6[i]=b7[i]=b8[i]=bx1[i]=bx2[i]=by1[i]=by4[i]=BLZ_FEHLER;
      is_not_digit[i]=1;
      leer_string[i]=(char*)"";
      leer_zahl[i]=-1;
      leer_char[i]=0;
      uk_pz_methoden[i]=0;
   }
   b0[0]=by1[0]=by4[0]=0;  /* b0 wird nur für das Nullbyte am Ende der BLZ benutzt */
   b0[' ']=b0['\t']=0;     /* für b0 auch Blank bzw. Tab akzeptieren */

      /* eigentliche Ziffern belegen */
   for(i='0';i<='9';i++){
      is_not_digit[i]=0;
      ziffer=i-'0';
      bx1[i]=by1[i]=b1[i]=ziffer; ziffer*=10;
      bx2[i]=b2[i]=ziffer; ziffer*=10;
      b3[i]=ziffer; ziffer*=10;
      by4[i]=b4[i]=ziffer; ziffer*=10;
      b5[i]=ziffer; ziffer*=10;
      b6[i]=ziffer; ziffer*=10;
      b7[i]=ziffer; ziffer*=10;
      b8[i]=ziffer;
   }
   for(i='a';i<'z';i++){ /* Sonderfall für bx1, bx2 und by4: Buchstaben a-z => 10...36 (Prüfziffermethoden) */
      bx1[i]=(i-'a'+10);   /* bx1: a...z => 10...36 */
      by1[i]=(i-'a'+1);    /* by1: a...z => 1...26 (für Untermethoden direkt) */
      bx2[i]=bx1[i]*10;    /* bx2: a...z => 100...360 (Prüfziffermethoden 1. Stelle) */
      by4[i]=(i-'a'+1)*1000;  /* Untermethode von Prüfziffern (in der Debugversion) */
   }
   for(i='A';i<='Z';i++){ /* wie oben, nur für Großbuchstaben */
      bx1[i]=(i-'A'+10);
      by1[i]=(i-'A'+1);
      bx2[i]=bx1[i]*10;
      by4[i]=(i-'A'+1)*1000;
   }

      /* Methoden, die weggelassene Unterkonten enthalten können */
   uk_pz_methoden[13]=uk_pz_methoden[26]=uk_pz_methoden[50]=uk_pz_methoden[63]=uk_pz_methoden[76]=uk_pz_methoden[127]=1; 

   for(i=0;i<=9;i++){   /* Hasharrays initialisieren */
      h1[i+'0']=hx1[i];
      h2[i+'0']=hx2[i];
      h3[i+'0']=hx3[i];
      h4[i+'0']=hx4[i];
      h5[i+'0']=hx5[i];
      h6[i+'0']=hx6[i];
      h7[i+'0']=hx7[i];
      h8[i+'0']=hx8[i];
   }
#if COMPRESS>0
   l=sizeof(ee);
   if(uncompress(ee,&l,eec,sizeof(eec))==Z_OK){
      eep=ee+1;
      eeh=ee+*ee;
   }
#endif

   for(i=0;i<255;i++){
      lut_block_name1[i]="  (unbekannt)";
      lut_block_name2[i]="  (unbekannt)";
      lut2_feld_namen[i]="";
   }
   lut_block_name2[0]="leer";

   lut2_feld_namen[LUT2_BLZ]="LUT2_BLZ";
   lut2_feld_namen[LUT2_2_BLZ]="LUT2_2_BLZ";
   lut2_feld_namen[LUT2_FILIALEN]="LUT2_FILIALEN";
   lut2_feld_namen[LUT2_2_FILIALEN]="LUT2_2_FILIALEN";
   lut2_feld_namen[LUT2_NAME]="LUT2_NAME";
   lut2_feld_namen[LUT2_2_NAME]="LUT2_2_NAME";
   lut2_feld_namen[LUT2_PLZ]="LUT2_PLZ";
   lut2_feld_namen[LUT2_2_PLZ]="LUT2_2_PLZ";
   lut2_feld_namen[LUT2_ORT]="LUT2_ORT";
   lut2_feld_namen[LUT2_2_ORT]="LUT2_2_ORT";
   lut2_feld_namen[LUT2_NAME_KURZ]="LUT2_NAME_KURZ";
   lut2_feld_namen[LUT2_2_NAME_KURZ]="LUT2_2_NAME_KURZ";
   lut2_feld_namen[LUT2_PAN]="LUT2_PAN";
   lut2_feld_namen[LUT2_2_PAN]="LUT2_2_PAN";
   lut2_feld_namen[LUT2_BIC]="LUT2_BIC";
   lut2_feld_namen[LUT2_2_BIC]="LUT2_2_BIC";
   lut2_feld_namen[LUT2_PZ]="LUT2_PZ";
   lut2_feld_namen[LUT2_2_PZ]="LUT2_2_PZ";
   lut2_feld_namen[LUT2_NR]="LUT2_NR";
   lut2_feld_namen[LUT2_2_NR]="LUT2_2_NR";
   lut2_feld_namen[LUT2_AENDERUNG]="LUT2_AENDERUNG";
   lut2_feld_namen[LUT2_2_AENDERUNG]="LUT2_2_AENDERUNG";
   lut2_feld_namen[LUT2_LOESCHUNG]="LUT2_LOESCHUNG";
   lut2_feld_namen[LUT2_2_LOESCHUNG]="LUT2_2_LOESCHUNG";
   lut2_feld_namen[LUT2_NACHFOLGE_BLZ]="LUT2_NACHFOLGE_BLZ";
   lut2_feld_namen[LUT2_2_NACHFOLGE_BLZ]="LUT2_2_NACHFOLGE_BLZ";
   lut2_feld_namen[LUT2_NAME_NAME_KURZ]="LUT2_NAME_NAME_KURZ";
   lut2_feld_namen[LUT2_2_NAME_NAME_KURZ]="LUT2_2_NAME_NAME_KURZ";
   lut2_feld_namen[LUT2_INFO]="LUT2_INFO";
   lut2_feld_namen[LUT2_2_INFO]="LUT2_2_INFO";
   lut2_feld_namen[LUT2_BIC_SORT]="LUT2_BIC_SORT";
   lut2_feld_namen[LUT2_2_BIC_SORT]="LUT2_2_BIC_SORT";
   lut2_feld_namen[LUT2_NAME_SORT]="LUT2_NAME_SORT";
   lut2_feld_namen[LUT2_2_NAME_SORT]="LUT2_2_NAME_SORT";
   lut2_feld_namen[LUT2_NAME_KURZ_SORT]="LUT2_NAME_KURZ_SORT";
   lut2_feld_namen[LUT2_2_NAME_KURZ_SORT]="LUT2_2_NAME_KURZ_SORT";
   lut2_feld_namen[LUT2_ORT_SORT]="LUT2_ORT_SORT";
   lut2_feld_namen[LUT2_2_ORT_SORT]="LUT2_2_ORT_SORT";
   lut2_feld_namen[LUT2_PLZ_SORT]="LUT2_PLZ_SORT";
   lut2_feld_namen[LUT2_2_PLZ_SORT]="LUT2_2_PLZ_SORT";
   lut2_feld_namen[LUT2_PZ_SORT]="LUT2_PZ_SORT";
   lut2_feld_namen[LUT2_2_PZ_SORT]="LUT2_2_PZ_SORT";
   lut2_feld_namen[LUT2_OWN_IBAN]="LUT2_OWN_IBAN";
   lut2_feld_namen[LUT2_2_OWN_IBAN]="LUT2_2_OWN_IBAN";
   lut2_feld_namen[LUT2_VOLLTEXT_TXT]="LUT2_VOLLTEXT_TXT";
   lut2_feld_namen[LUT2_2_VOLLTEXT_TXT]="LUT2_2_VOLLTEXT_TXT";
   lut2_feld_namen[LUT2_VOLLTEXT_IDX]="LUT2_VOLLTEXT_IDX";
   lut2_feld_namen[LUT2_2_VOLLTEXT_IDX]="LUT2_2_VOLLTEXT_IDX";
   lut2_feld_namen[LUT2_IBAN_REGEL]="LUT2_IBAN_REGEL";
   lut2_feld_namen[LUT2_2_IBAN_REGEL]="LUT2_2_IBAN_REGEL";
   lut2_feld_namen[LUT2_IBAN_REGEL_SORT]="LUT2_IBAN_REGEL_SORT";
   lut2_feld_namen[LUT2_2_IBAN_REGEL_SORT]="LUT2_2_IBAN_REGEL_SORT";
   lut2_feld_namen[LUT2_BIC_H_SORT]="LUT2_BIC_H_SORT";
   lut2_feld_namen[LUT2_2_BIC_H_SORT]="LUT2_2_BIC_H_SORT";

   lut_block_idx[1]=0;
   lut_block_idx[2]=0;
   lut_block_idx[3]=1;
   lut_block_idx[4]=1;
   lut_block_idx[5]=1;
   lut_block_idx[6]=1;
   lut_block_idx[7]=0;
   lut_block_idx[8]=1;
   lut_block_idx[9]=1;
   lut_block_idx[10]=0;
   lut_block_idx[11]=0;
   lut_block_idx[12]=0;
   lut_block_idx[13]=0;
   lut_block_idx[14]=1;
   lut_block_idx[15]=0;
   lut_block_idx[16]=0;
   lut_block_idx[17]=0;
   lut_block_idx[18]=0;
   lut_block_idx[19]=0;
   lut_block_idx[20]=0;
   lut_block_idx[21]=0;
   lut_block_idx[22]=0;
   lut_block_idx[23]=0;
   lut_block_idx[24]=0;
   lut_block_idx[25]=0;
   lut_block_idx[26]=0;
   lut_block_idx[27]=0;

   lut_block_name1[1]="BLZ";
   lut_block_name1[2]="FILIALEN";
   lut_block_name1[3]="NAME";
   lut_block_name1[4]="PLZ";
   lut_block_name1[5]="ORT";
   lut_block_name1[6]="NAME_KURZ";
   lut_block_name1[7]="PAN";
   lut_block_name1[8]="BIC";
   lut_block_name1[9]="PZ";
   lut_block_name1[10]="NR";
   lut_block_name1[11]="AENDERUNG";
   lut_block_name1[12]="LOESCHUNG";
   lut_block_name1[13]="NACHFOLGE_BLZ";
   lut_block_name1[14]="NAME_NAME_KURZ";
   lut_block_name1[15]="INFO";
   lut_block_name1[16]="BIC_SORT";
   lut_block_name1[17]="NAME_SORT";
   lut_block_name1[18]="NAME_KURZ_SORT";
   lut_block_name1[19]="ORT_SORT";
   lut_block_name1[20]="PLZ_SORT";
   lut_block_name1[21]="PZ_SORT";
   lut_block_name1[22]="OWN_IBAN";
   lut_block_name1[23]="VOLLTEXT_TXT";
   lut_block_name1[24]="VOLLTEXT_IDX";
   lut_block_name1[25]="IBAN_REGEL";
   lut_block_name1[26]="IBAN_REGEL_SORT";
   lut_block_name1[27]="BIC_H_SORT";
   lut_block_name1[101]="BLZ (2)";
   lut_block_name1[102]="FILIALEN (2)";
   lut_block_name1[103]="NAME (2)";
   lut_block_name1[104]="PLZ (2)";
   lut_block_name1[105]="ORT (2)";
   lut_block_name1[106]="NAME_KURZ (2)";
   lut_block_name1[107]="PAN (2)";
   lut_block_name1[108]="BIC (2)";
   lut_block_name1[109]="PZ (2)";
   lut_block_name1[110]="NR (2)";
   lut_block_name1[111]="AENDERUNG (2)";
   lut_block_name1[112]="LOESCHUNG (2)";
   lut_block_name1[113]="NACHFOLGE_BLZ (2)";
   lut_block_name1[114]="NAME_NAME_KURZ (2)";
   lut_block_name1[115]="INFO (2)";
   lut_block_name1[116]="BIC_SORT (2)";
   lut_block_name1[117]="NAME_SORT (2)";
   lut_block_name1[118]="NAME_KURZ_SORT (2)";
   lut_block_name1[119]="ORT_SORT (2)";
   lut_block_name1[120]="PLZ_SORT (2)";
   lut_block_name1[121]="PZ_SORT (2)";
   lut_block_name1[122]="OWN_IBAN (2)";
   lut_block_name1[123]="VOLLTEXT_TXT (2)";
   lut_block_name1[124]="VOLLTEXT_IDX (2)";
   lut_block_name1[125]="IBAN_REGEL (2)";
   lut_block_name1[126]="IBAN_REGEL_SORT (2)";
   lut_block_name1[127]="BIC_H_SORT (2)";

   lut_block_name2[1]="1. BLZ";
   lut_block_name2[2]="1. Anzahl Fil.";
   lut_block_name2[3]="1. Name";
   lut_block_name2[4]="1. Plz";
   lut_block_name2[5]="1. Ort";
   lut_block_name2[6]="1. Name (kurz)";
   lut_block_name2[7]="1. PAN";
   lut_block_name2[8]="1. BIC";
   lut_block_name2[9]="1. Pruefziffer";
   lut_block_name2[10]="1. Lfd. Nr.";
   lut_block_name2[11]="1. Aenderung";
   lut_block_name2[12]="1. Loeschung";
   lut_block_name2[13]="1. NachfolgeBLZ";
   lut_block_name2[14]="1. Name, Kurzn.";
   lut_block_name2[15]="1. Infoblock";
   lut_block_name2[16]="1. BIC idx";
   lut_block_name2[17]="1. Name idx";
   lut_block_name2[18]="1. Kurzname idx";
   lut_block_name2[19]="1. Ort idx";
   lut_block_name2[20]="1. PLZ idx";
   lut_block_name2[21]="1. PZ idx";
   lut_block_name2[22]="1. IBAN Blacklist";
   lut_block_name2[23]="1. Volltext txt";
   lut_block_name2[24]="1. Volltext idx";
   lut_block_name2[25]="1. IBAN Regel";
   lut_block_name2[26]="1. IBAN Regel idx";
   lut_block_name2[27]="1. BIC Hauptst.idx";
   lut_block_name2[101]="2. BLZ";
   lut_block_name2[102]="2. Anzahl Fil.";
   lut_block_name2[103]="2. Name";
   lut_block_name2[104]="2. Plz";
   lut_block_name2[105]="2. Ort";
   lut_block_name2[106]="2. Name (kurz)";
   lut_block_name2[107]="2. PAN";
   lut_block_name2[108]="2. BIC";
   lut_block_name2[109]="2. Pruefziffer";
   lut_block_name2[110]="2. Lfd. Nr.";
   lut_block_name2[111]="2. Aenderung";
   lut_block_name2[112]="2. Loeschung";
   lut_block_name2[113]="2. NachfolgeBLZ";
   lut_block_name2[114]="2. Name, Kurzn.";
   lut_block_name2[115]="2. Infoblock";
   lut_block_name2[116]="2. BIC idx";
   lut_block_name2[117]="2. Name idx";
   lut_block_name2[118]="2. Kurzname idx";
   lut_block_name2[119]="2. Ort idx";
   lut_block_name2[120]="2. PLZ idx";
   lut_block_name2[121]="2. PZ idx";
   lut_block_name2[122]="2. IBAN Blacklist";
   lut_block_name2[123]="2. Volltext txt";
   lut_block_name2[124]="2. Volltext idx";
   lut_block_name2[125]="2. IBAN Regel";
   lut_block_name2[126]="2. IBAN Regel idx";
   lut_block_name2[127]="2. BIC Hauptst.idx";
   lut_blocklen_max=453;
   init_status|=1;
}

/* Funktion kto_check_int() +§§§1
   Prolog +§§§2 */
/* ###########################################################################
 * # Die Funktion kto_check_int() ist die interne Funktion zur Überprüfung   #
 * # einer Kontonummer. Ab Version 3.0 wurde die Funktionalität umgestellt,  #
 * # indem Initialisierung und Test getrennt wurden; diese Routine führt nur #
 * # noch die Tests durch, macht keine Initialisierung mehr.                 #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    x_blz:        Bankleitzahl (wird in einigen Methoden benötigt)       #
 * #    pz_methode:   Prüfziffer (numerisch)                                 #
 * #    kto:          Kontonummer                                            #
 * #                                                                         #
 * # (die beiden folgenden Parameter werden nur in der DEBUG-Version         #
 * #  unterstützt):                                                          #
 * #                                                                         #
 * #    untermethode: gewünschte Untermethode oder 0                         #
 * #    retvals:      Struktur, um Prüfziffermethode und Prüfziffer in einer #
 * #                  threadfesten Version zurückzugeben                     #
 * #                                                                         #
 * # Copyright (C) 2002-2009 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

#if DEBUG>0
static int kto_check_int(char *x_blz,int pz_methode,char *kto,int untermethode,RETVAL *retvals)
#else
static int kto_check_int(char *x_blz,int pz_methode,char *kto)
#endif
{
   char *ptr,*dptr,kto_alt[32],xkto[32];
   int i,p1=0,tmp,kto_len,pz1=0,ok,pz;
   int c2,d2,a5,p,konto[11];   /* Variablen für Methode 87 */

      /* Konto links mit Nullen auf 10 Stellen auffüllen,
       * und in die lokale Variable xkto umkopieren.
       */
   memset(xkto,'0',12);
   for(ptr=kto;*ptr=='0' || *ptr==' ' || *ptr=='\t';ptr++);
   for(kto_len=0;*ptr && *ptr!=' ' && *ptr!='\t';kto_len++,ptr++);
   if(kto_len<1 || kto_len>10)RETURN(INVALID_KTO_LENGTH);
   dptr=xkto+10;
   *dptr--=0;
   for(ptr--,i=kto_len;i-->0;*dptr--= *ptr--);
   kto=xkto;

/* Methoden der Prüfzifferberechnung +§§§2
   Prolog +§§§3 */
/*
 * ######################################################################
 * #               Methoden der Prüfzifferberechnung                    #
 * ######################################################################
 */

   switch(pz_methode){

/* Berechnungsmethoden 00 bis 09 +§§§3
   Berechnung nach der Methode 00 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 00                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2.                  #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach         #
 * # links mit den Ziffern 2, 1, 2, 1, 2 usw. zu multiplizieren.        #
 * # Die jeweiligen Produkte werden addiert, nachdem jeweils aus        #
 * # den zweistelligen Produkten die Quersumme gebildet wurde           #
 * # (z.B. Produkt 16 = Quersumme 7). Nach der Addition bleiben         #
 * # außer der Einerstelle alle anderen Stellen unberücksichtigt.       #
 * # Die Einerstelle wird von dem Wert 10 subtrahiert. Das Ergebnis     #
 * # ist die Prüfziffer. Ergibt sich nach der Subtraktion der           #
 * # Rest 10, ist die Prüfziffer 0.                                     #
 * ######################################################################
 */

      case 0:
#if DEBUG>0
         if(retvals){
            retvals->methode="00";
            retvals->pz_methode=0;
         }
#endif

            /* Alpha: etwas andere Berechnung, wesentlich schneller
             * (benötigt nur 75 statt 123 Takte, falls Berechnung wie Intel.
             * Die Intel-Methode wäre somit sogar langsamer als die alte Version
             * mit 105 Takten)
             */
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;


/*  Berechnung nach der Methode 01 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 01                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 3, 7, 1, 3, 7, 1, 3, 7, 1.                  #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach         #
 * # links mit den Ziffern 3, 7, 1, 3, 7, 1 usw. zu multiplizieren.     #
 * # Die jeweiligen Produkte werden addiert. Nach der Addition          #
 * # bleiben außer der Einerstelle alle anderen Stellen                 #
 * # Unberücksichtigt. Die Einerstelle wird von dem Wert 10             #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Ergibt sich nach     #
 * # der Subtraktion der Rest 10, ist die Prüfziffer 0.                 #
 * ######################################################################
 */
      case 1:
#if DEBUG>0
         if(retvals){
            retvals->methode="01";
            retvals->pz_methode=1;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 7
            + (kto[2]-'0') * 3
            + (kto[3]-'0')
            + (kto[4]-'0') * 7
            + (kto[5]-'0') * 3
            + (kto[6]-'0')
            + (kto[7]-'0') * 7
            + (kto[8]-'0') * 3;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 02 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 02                       #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 2.                  #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach         #
 * # links mit den Ziffern 2, 3, 4, 5, 6, 7, 8, 9, 2 zu                 #
 * # multiplizieren. Die jeweiligen Produkte werden addiert.            #
 * # Die Summe ist durch 11 zu dividieren. Der verbleibende Rest        #
 * # wird vom Divisor (11) subtrahiert. Das Ergebnis ist die            #
 * # Prüfziffer. Verbleibt nach der Division durch 11 kein Rest,        #
 * # ist die Prüfziffer 0. Ergibt sich als Rest 1, ist die              #
 * # Prüfziffer zweistellig und kann nicht verwendet werden.            #
 * # Die Kontonummer ist dann nicht verwendbar.                         #
 * ######################################################################
 */
      case 2:
#if DEBUG>0
         if(retvals){
            retvals->methode="02";
            retvals->pz_methode=2;
         }
#endif
         pz = (kto[0]-'0') * 2
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz)pz=11-pz;
         INVALID_PZ10;
         CHECK_PZ10;

/*  Berechnung nach der Methode 03 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 03                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2.                  #
 * # Die Berechnung erfolgt wie bei Verfahren 01.                       #
 * ######################################################################
 */
      case 3:
#if DEBUG>0
         if(retvals){
            retvals->methode="03";
            retvals->pz_methode=3;
         }
#endif
         pz = (kto[0]-'0') * 2
            + (kto[1]-'0')
            + (kto[2]-'0') * 2
            + (kto[3]-'0')
            + (kto[4]-'0') * 2
            + (kto[5]-'0')
            + (kto[6]-'0') * 2
            + (kto[7]-'0')
            + (kto[8]-'0') * 2;

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 04 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 04                       #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4.                  #
 * # Die Berechnung erfolgt wie bei Verfahren 02.                       #
 * ######################################################################
 */
      case 4:
#if DEBUG>0
         if(retvals){
            retvals->methode="04";
            retvals->pz_methode=4;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz)pz=11-pz;
         INVALID_PZ10;
         CHECK_PZ10;

/*  Berechnung nach der Methode 05 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 05                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 7, 3, 1, 7, 3, 1, 7, 3, 1.                  #
 * # Die Berechnung erfolgt wie bei Verfahren 01.                       #
 * ######################################################################
 */
      case 5:
#if DEBUG>0
         if(retvals){
            retvals->methode="05";
            retvals->pz_methode=5;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 7
            + (kto[3]-'0')
            + (kto[4]-'0') * 3
            + (kto[5]-'0') * 7
            + (kto[6]-'0')
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 7;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 06 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 06                       #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7 (modifiziert)              #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach         #
 * # links mit den Ziffern 2, 3, 4, 5, 6, 7, 2, 3 ff. zu multiplizieren.#
 * # Die jeweiligen Produkte werden addiert. Die Summe ist              #
 * # durch 11 zu dividieren. Der verbleibende Rest wird vom             #
 * # Divisor (11) subtrahiert. Das Ergebnis ist die Prüfziffer.         #
 * # Ergibt sich als Rest 1, findet von dem Rechenergebnis 10           #
 * # nur die Einerstelle (0) als Prüfziffer Verwendung. Verbleibt       #
 * # nach der Division durch 11 kein Rest, dann ist auch die            #
 * # Prüfziffer 0. Die Stelle 10 der Kontonummer ist die Prüfziffer.    #
 * ######################################################################
 */
      case 6:
#if DEBUG>0
         if(retvals){
            retvals->methode="06";
            retvals->pz_methode=6;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 07 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 07                       #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10.                 #
 * # Die Berechnung erfolgt wie bei Verfahren 02.                       #
 * ######################################################################
 */
      case 7:
#if DEBUG>0
         if(retvals){
            retvals->methode="07";
            retvals->pz_methode=7;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz)pz=11-pz;
         INVALID_PZ10;
         CHECK_PZ10;

/*  Berechnung nach der Methode 08 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 08                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2 (modifiziert).    #
 * # Die Berechnung erfolgt wie bei Verfahren 00, jedoch erst           #
 * # ab der Kontonummer 60 000.                                         #
 * ######################################################################
 */
      case 8:
#if DEBUG>0
         if(retvals){
            retvals->methode="08";
            retvals->pz_methode=8;
         }
#endif
         if(strcmp(kto,"0000060000")<0)  /* Kontonummern unter 60 000: keine Prüfzifferberechnung oder falsch??? */
            RETURN(INVALID_KTO);
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 09 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 09                       #
 * ######################################################################
 * # Keine Prüfziffernberechung (es wird immer richtig zurückgegeben).  #
 * ######################################################################
 */
      case 9:
#if DEBUG>0
         if(retvals){
            retvals->methode="09";
            retvals->pz_methode=9;
         }
#endif
         return OK_NO_CHK;

/* Berechnungsmethoden 10 bis 19 +§§§3
   Berechnung nach der Methode 10 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode 10                       #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10 (modifiziert).   #
 * # Die Berechnung erfolgt wie bei Verfahren 06.                       #
 * ######################################################################
 */
      case 10:
#if DEBUG>0
         if(retvals){
            retvals->methode="10";
            retvals->pz_methode=10;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 11 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 11                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10 (modifiziert).   #
 * # Die Berechnung erfolgt wie bei Verfahren 06. Beim Rechenergebnis   #
 * # 10 wird die Null jedoch durch eine 9 ersetzt.                      #
 * ######################################################################
 */
      case 11:
#if DEBUG>0
         if(retvals){
            retvals->methode="11";
            retvals->pz_methode=11;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz==1)
            pz=9;
         else if(pz>1)
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 12 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 12                        #
 * ######################################################################
 * # frei/nicht definiert                                               #
 * # Beim Aufruf dieser Methode wird grundsätzlich ein Fehler zurück-   #
 * # gegeben, um nicht eine (evl. falsche) Implementation vorzutäuschen.#
 * ######################################################################
 */
      case 12:
#if DEBUG>0
         if(retvals){
            retvals->methode="12";
            retvals->pz_methode=12;
         }
#endif
         return NOT_DEFINED;

/*  Berechnung nach der Methode 13 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 13                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1.                           #
 * # Die Berechnung erfolgt wie bei Verfahren 00. Es ist jedoch zu      #
 * # beachten, daß die zweistellige Unterkonto-Nummer (Stellen 9        #
 * # und 10) nicht in das Prüfziffernberechnungsverfahren mit           #
 * # einbezogen werden darf. Die für die Berechnung relevante           #
 * # sechsstellige Grundnummer befindet sich in den Stellen 2 bis 7,    #
 * # die Prüfziffer in Stelle 8. Die Kontonummer ist neunstellig,       #
 * # Stelle 1 ist also unbenutzt.                                       #
 * # Ist die obengenannte Unternummer = 00 kommt es vor, daß sie        #
 * # auf den Zahlungsverkehrsbelegen nicht angegeben ist. Ergibt        #
 * # die erste Berechnung einen Prüfziffernfehler, wird empfohlen,      #
 * # die Prüfziffernberechnung ein zweites Mal durchzuführen und        #
 * # dabei die "gedachte" Unternummer 00 zu berücksichtigen.            #
 * ######################################################################
 */
      case 13:
#if DEBUG>0
      case 1013:
         if(retvals){
            retvals->methode="13a";
            retvals->pz_methode=1013;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX8;

            /* falls die beiden ersten Stellen der Kontonummer nicht 00 sind,
             * kann keine Unterkontonummer weggelassen sein; in dem Fall FALSE
             * zurückgeben.
             */
         if(kto[0]!='0' || kto[1]!='0')return FALSE;

#if DEBUG>0
      case 2013:
         if(retvals){
            retvals->methode="13b";
            retvals->pz_methode=2013;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 14 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 14                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7.                           #
 * # Die Berechnung erfolgt wie bei Verfahren 02. Es ist jedoch zu      #
 * # beachten, daß die zweistellige Kontoart nicht in das Prüfziffern-  #
 * # berechnungsverfahren mit einbezogen wird. Die Kontoart belegt      #
 * # die Stellen 2 und 3, die zu berechnende Grundnummer die Stellen    #
 * # 4 bis 9. Die Prüfziffer befindet sich in Stelle 10.                #
 * ######################################################################
 */
      case 14:
#if DEBUG>0
         if(retvals){
            retvals->methode="14";
            retvals->pz_methode=14;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz)pz=11-pz;
         INVALID_PZ10;
         CHECK_PZ10;

/*  Berechnung nach der Methode 15 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 15                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5.                                 #
 * # Die Berechnung erfolgt wie bei Verfahren 06. Es ist jedoch zu      #
 * # beachten, daß nur die vierstellige Kontonummer in das              #
 * # Prüfziffernberechnungsverfahren einbezogen wird. Sie befindet      #
 * # sich in den Stellen 6 bis 9, die Prüfziffer in Stelle 10           #
 * # der Kontonummer.                                                   #
 * ######################################################################
 */
      case 15:
#if DEBUG>0
         if(retvals){
            retvals->methode="15";
            retvals->pz_methode=15;
         }
#endif
         pz = (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_88;    /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 16 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 16                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #
 * # Die Berechnung erfolgt wie bei Verfahren 06. Sollte sich jedoch    #
 * # nach der Division der Rest 1 ergeben, so ist die Kontonummer       #
 * # unabhängig vom eigentlichen Berechnungsergebnis                    #
 * # richtig, wenn die Ziffern an 10. und 9. Stelle identisch sind.     #
 * ######################################################################
 */
      case 16:
#if DEBUG>0
         if(retvals){
            retvals->methode="16";
            retvals->pz_methode=16;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz)pz=11-pz;
         if(pz==10){
#if DEBUG>0
            if(retvals){
               retvals->pz_pos=10;
               retvals->pz=*(kto+8)-'0';
            }
#endif
            if(*(kto+8)== *(kto+9))
               return OK;
            else
               /* die Frage hier ist, was ist wenn 9. und 10. Stelle
                * unterschiedlich sind aber das Ergebnis von Verfahren 6
                * akzeptiert würde? Markus nimmt das Beispiel aus Verfahren 23
                * her (das auf Verfahren 16 aufbaut); da wird explizit gesagt,
                * falls die Stellen 6 und 7 (entsprechen hier den Stellen 9 und
                * 10) nicht übereinstimmen, ist das Konto als falsch zu werten.
                * Ich benutze den fallback zu Version 6 und nehme als
                * Prüfziffer 0. Die Frage müßte von den Banken geklärt werden,
                * der Text gibt es nicht her.
                *
                * Update 2.8.2013: Sowohl der SEPA IBAN Konverter der Sparkassen als
                * auch der VR IBAN Konverter melden bei diesen Konten 11 (Fehler in
                * der Kontonummer); daher wird von konto_check jetzt auch FALSE
                * zurückgegeben.
                */
               return FALSE;
#if 0
                  /* alte Version */
#if BAV_KOMPATIBEL
               return BAV_FALSE;
#else
               pz=0;
#endif
#endif
         }
         CHECK_PZ10;

/*  Berechnung nach der Methode 17 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 17                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 1, 2, 1, 2, 1, 2                            #
 * # Die Kontonummer ist 10-stellig mit folgendem Aufbau:               #
 * #                                                                    #
 * #     KSSSSSSPUU                                                     #
 * #     K = Kontoartziffer                                             #
 * #     S = Stammnummer                                                #
 * #     P = Prüfziffer                                                 #
 * #     U = Unterkontonummer                                           #
 * #                                                                    #
 * # Die für die Berechnung relevante 6-stellige Stammnummer            #
 * # (Kundennummer) befindet sich in den Stellen 2 bis 7 der            #
 * # Kontonummer, die Prüfziffer in der Stelle 8. Die einzelnen         #
 * # Stellen der Stammnummer (S) sind von links nach rechts mit         #
 * # den Ziffern 1, 2, 1, 2, 1, 2 zu multiplizieren. Die                #
 * # jeweiligen Produkte sind zu addieren, nachdem aus eventuell        #
 * # zweistelligen Produkten der 2., 4. und 6. Stelle der               #
 * # Stammnummer die Quersumme gebildet wurde. Von der Summe ist        #
 * # der Wert "1" zu subtrahieren. Das Ergebnis ist dann durch          #
 * # 11 zu dividieren. Der verbleibende Rest wird von 10                #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt            #
 * # nach der Division durch 11 kein Rest, ist die Prüfziffer 0.        #
 * ######################################################################
 */

      case 17:
#if DEBUG>0
         if(retvals){
            retvals->methode="17";
            retvals->pz_methode=17;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif

         pz-=1;
         MOD_11_44;   /* pz%=11 */
         if(pz)pz=10-pz;
         CHECK_PZ8;

/*  Berechnung nach der Methode 18 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 18                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 3, 9, 7, 1, 3, 9, 7, 1, 3.                  #
 * # Die Berechnung erfolgt wie bei Verfahren 01.                       #
 * ######################################################################
 */
      case 18:
#if DEBUG>0
         if(retvals){
            retvals->methode="18";
            retvals->pz_methode=18;
         }
#endif
         pz = (kto[0]-'0') * 3
            + (kto[1]-'0')
            + (kto[2]-'0') * 7
            + (kto[3]-'0') * 9
            + (kto[4]-'0') * 3
            + (kto[5]-'0')
            + (kto[6]-'0') * 7
            + (kto[7]-'0') * 9
            + (kto[8]-'0') * 3;

         MOD_10_320;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 19 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 19                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 1.                  #
 * # Die Berechnung erfolgt wie bei Verfahren 06.                       #
 * ######################################################################
 */
      case 19:
#if DEBUG>0
         if(retvals){
            retvals->methode="19";
            retvals->pz_methode=19;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/* Berechnungsmethoden 20 bis 29 +§§§3
   Berechnung nach der Methode 20 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 20                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 3 (modifiziert).    #
 * # Die Berechnung erfolgt wie bei Verfahren 06.                       #
 * ######################################################################
 */
      case 20:
#if DEBUG>0
         if(retvals){
            retvals->methode="20";
            retvals->pz_methode=20;
         }
#endif
         pz = (kto[0]-'0') * 3
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 21 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 21                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2 (modifiziert).    #
 * # Die Berechnung erfolgt wie bei Verfahren 00. Nach der Addition     #
 * # der Produkte werden neben der Einerstelle jedoch alle Stellen      #
 * # berücksichtigt, indem solange Quersummen gebildet werden, bis      #
 * # ein einstelliger Wert verbleibt. Die Differenz zwischen diesem     #
 * # Wert und dem Wert 10 ist die Prüfziffer.                           #
 * ######################################################################
 */
      case 21:
#if DEBUG>0
         if(retvals){
            retvals->methode="21";
            retvals->pz_methode=21;
         }
#endif
         pz = (kto[0]-'0') * 2
            + (kto[1]-'0')
            + (kto[2]-'0') * 2
            + (kto[3]-'0')
            + (kto[4]-'0') * 2
            + (kto[5]-'0')
            + (kto[6]-'0') * 2
            + (kto[7]-'0')
            + (kto[8]-'0') * 2;

         if(pz>=80)pz=pz-80+8;
         if(pz>=40)pz=pz-40+4;
         if(pz>=20)pz=pz-20+2;
         if(pz>=10)pz=pz-10+1;
         if(pz>=10)pz=pz-10+1;
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 22 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 22                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 3, 1, 3, 1, 3, 1, 3, 1, 3.                  #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach         #
 * # links mit den Ziffern 3, 1, 3, 1 usw. zu multiplizieren.           #
 * # Von den jeweiligen Produkten bleiben die Zehnerstellen             #
 * # unberücksichtigt. Die verbleibenden Zahlen (Einerstellen)          #
 * # werden addiert. Die Differenz bis zum nächsten Zehner ist          #
 * # die Prüfziffer.                                                    #
 * ######################################################################
 */
      case 22:
#if DEBUG>0
         if(retvals){
            retvals->methode="22";
            retvals->pz_methode=22;
         }
#endif
         pz = (kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');

            if(kto[0]<'4')
               pz+=(kto[0]-'0')*3;
            else if(kto[0]<'7')
               pz+=(kto[0]-'0')*3-10;
            else
               pz+=(kto[0]-'0')*3-20;

            if(kto[2]<'4')
               pz+=(kto[2]-'0')*3;
            else if(kto[2]<'7')
               pz+=(kto[2]-'0')*3-10;
            else
               pz+=(kto[2]-'0')*3-20;

            if(kto[4]<'4')
               pz+=(kto[4]-'0')*3;
            else if(kto[4]<'7')
               pz+=(kto[4]-'0')*3-10;
            else
               pz+=(kto[4]-'0')*3-20;

            if(kto[6]<'4')
               pz+=(kto[6]-'0')*3;
            else if(kto[6]<'7')
               pz+=(kto[6]-'0')*3-10;
            else
               pz+=(kto[6]-'0')*3-20;

            if(kto[8]<'4')
               pz+=(kto[8]-'0')*3;
            else if(kto[8]<'7')
               pz+=(kto[8]-'0')*3-10;
            else
               pz+=(kto[8]-'0')*3-20;

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 23 +§§§4 */
/*
 * ######################################################################
 * #     Berechnung nach der Methode 23 (geändert zum 3.9.2001)         #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7.                           #
 * # Das Prüfziffernverfahren entspricht dem der Kennziffer 16,         #
 * # wird jedoch nur auf die ersten sechs Ziffern der Kontonummer       #
 * # angewandt. Die Prüfziffer befindet sich an der 7. Stelle der       #
 * # Kontonummer. Die drei folgenden Stellen bleiben ungeprüft.         #
 * # Sollte sich nach der Division der Rest 1 ergeben, so ist           #
 * # die Kontonummer unabhängig vom eigentlichen Berechnungsergebnis    #
 * # richtig, wenn die Ziffern an 6. und 7. Stelle identisch sind.      #
 * ######################################################################
 */
      case 23:
#if DEBUG>0
         if(retvals){
            retvals->methode="23";
            retvals->pz_methode=23;
         }
#endif
         pz = (kto[0]-'0') * 7
            + (kto[1]-'0') * 6
            + (kto[2]-'0') * 5
            + (kto[3]-'0') * 4
            + (kto[4]-'0') * 3
            + (kto[5]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz)pz=11-pz;
         if(pz==10){
#if DEBUG>0
            if(retvals){
               retvals->pz_pos=7;
               retvals->pz=*(kto+6)-'0';
            }
#endif
            if(*(kto+5)==*(kto+6))
               return OK;
            else
               return FALSE;
         }
         CHECK_PZ7;

/*  Berechnung nach der Methode 24 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 24                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 1, 2, 3, 1, 2, 3, 1, 2, 3                   #
 * # Die für die Berechnung relevanten Stellen der Kontonummer          #
 * # befinden sich in den Stellen 1 - 9 und die Prüfziffer in           #
 * # Stelle 10 des zehnstelligen Kontonummernfeldes. Eine evtl.         #
 * # in Stelle 1 vorhandene Ziffer 3, 4, 5, 6 wird wie 0 gewertet.      #
 * # Eine ggf. in Stelle 1 vorhandene Ziffer 9 wird als 0 gewertet und  #
 * # führt dazu, dass auch die beiden nachfolgenden Ziffern in den      #
 * # Stellen 2 und 3 der Kontonummer als 0 gewertet werden müssen. Der  #
 * # o. g. Prüfalgorithmus greift in diesem Fall also erst ab Stelle 4  #
 * # der 10stelligen Kontonummer. Die Stelle 4 ist ungleich 0.          #
 * #                                                                    #
 * # Die einzelnen Stellen der Kontonummer sind von                     #
 * # links nach rechts, beginnend mit der ersten signifikanten          #
 * # Ziffer (Ziffer ungleich 0) in den Stellen 1 - 9, mit den           #
 * # Ziffern 1, 2, 3, 1, 2, 3, 1, 2, 3 zu multiplizieren. Zum           #
 * # jeweiligen Produkt ist die entsprechende Gewichtungsziffer         #
 * # zu addieren (zum ersten Produkt + 1; zum zweiten Produkt + 2;      #
 * # zum dritten Produkt +3; zum vierten Produkt + 1 usw.).             #
 * # Die einzelnen Rechenergebnisse sind durch 11 zu dividieren.        #
 * # Die sich nach der Division ergebenden Reste sind zu summieren.     #
 * # Die Summe der Reste ist durch 10 zu dividieren. Der sich           #
 * # danach ergebende Rest ist die Prüfziffer.                          #
 * ######################################################################
 */
      case 24:
#if DEBUG>0
         if(retvals){
            retvals->methode="24";
            retvals->pz_methode=24;
         }
#endif
         if(*kto>='3' && *kto<='6')*kto='0';
         if(*kto=='9')*kto= *(kto+1)= *(kto+2)='0';
         for(ptr=kto;*ptr=='0';ptr++);
         for(i=0,pz=0;ptr<kto+9;ptr++,i++){
            p1=(*ptr-'0')*w24[i]+w24[i];
            SUB1_22; /* p1%=11 */
            pz+=p1;
         }
         MOD_10_80;     /* pz%=10 */
         CHECK_PZ10;

/*  Berechnung nach der Methode 25 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 25                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9 ohne Quersumme.      #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach         #
 * # links mit den Ziffern 2, 3, 4, 5, 6, 7, 8, 9 zu multiplizieren.    #
 * # Die jeweiligen Produkte werden addiert. Die Summe ist durch        #
 * # 11 zu dividieren. Der verbleibende Rest wird vom Divisor (11)      #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt nach       #
 * # der Division durch 11 kein Rest, ist die Prüfziffer 0.             #
 * # Ergibt sich als Rest 1, ist die Prüfziffer immer 0 und kann        #
 * # nur für die Arbeitsziffer 8 und 9 verwendet werden. Die            #
 * # Kontonummer ist für die Arbeitsziffer 0, 1, 2, 3, 4, 5, 6          #
 * # und 7 dann nicht verwendbar.                                       #
 * # Die Arbeitsziffer (Geschäftsbereich oder Kontoart) befindet        #
 * # sich in der 2. Stelle (von links) des zehnstelligen                #
 * # Kontonummernfeldes.                                                #
 * ######################################################################
 */
      case 25:
#if DEBUG>0
         if(retvals){
            retvals->methode="25";
            retvals->pz_methode=25;
         }
#endif
         pz = (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz)pz=11-pz;
         if(pz==10){
            pz=0;
            if(*(kto+1)!='8' && *(kto+1)!='9')return INVALID_KTO;
         }
         CHECK_PZ10;

/*  Berechnung nach der Methode 26 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 26                        #
 * ######################################################################
 * # Modulus 11. Gewichtung 2, 3, 4, 5, 6, 7, 2                         #
 * # Die Kontonummer ist 10-stellig. Sind Stelle 1 und 2 mit            #
 * # Nullen gefüllt ist die Kontonummer um 2 Stellen nach links         #
 * # zu schieben und Stelle 9 und 10 mit Nullen zu füllen. Die          #
 * # Berechnung erfolgt wie bei Verfahren 06 mit folgender              #
 * # Modifizierung: für die Berechnung relevant sind die Stellen 1-7;   #
 * # die Prüfziffer steht in Stelle 8. Bei den Stellen 9 und 10 handelt #
 * # es sich um eine Unterkontonummer, welche für die Berechnung  nicht #
 * # berücksichtigt wird.                                               #
 * ######################################################################
 */
      case 26:
#if DEBUG>0
         if(retvals){
            retvals->methode="26";
            retvals->pz_methode=26;
         }
#endif
         if(*kto=='0' && *(kto+1)=='0'){
            /* Unterkontonummer ausgelassen */
         pz = (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else{
            pz = (kto[0]-'0') * 2
               + (kto[1]-'0') * 7
               + (kto[2]-'0') * 6
               + (kto[3]-'0') * 5
               + (kto[4]-'0') * 4
               + (kto[5]-'0') * 3
               + (kto[6]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ8;
         }

/*  Berechnung nach der Methode 27 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 27                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2 (modifiziert).    #
 * # Die Berechnung erfolgt wie bei Verfahren 00, jedoch nur für        #
 * # die Kontonummern von 1 bis 999.999.999. Ab Konto 1.000.000.000     #
 * # kommt das Prüfziffernverfahren M10H (Iterierte Transformation)     #
 * # zum Einsatz.                                                       #
 * # Es folgt die Beschreibung der iterierten Transformation:           #
 * # Die Position der einzelnen Ziffer von rechts nach links            #
 * # innerhalb der Kontonummer gibt die Zeile 1 bis 4 der               #
 * # Transformationstabelle an. Aus ihr sind die Übersetzungswerte      #
 * # zu summieren. Die Einerstelle wird von 10 subtrahiert und          #
 * # stellt die Prüfziffer dar.                                         #
 * # Transformationstabelle:                                            #
 * #    Ziffer    0 1 2 3 4 5 6 7 8 9                                   #
 * #    Ziffer 1  0 1 5 9 3 7 4 8 2 6                                   #
 * #    Ziffer 2  0 1 7 6 9 8 3 2 5 4                                   #
 * #    Ziffer 3  0 1 8 4 6 2 9 5 7 3                                   #
 * #    Ziffer 4  0 1 2 3 4 5 6 7 8 9                                   #
 * ######################################################################
 */
      case 27:
#if DEBUG>0
         if(retvals){
            retvals->methode="27";
            retvals->pz_methode=27;
         }
#endif
         if(*kto=='0'){ /* Kontonummern von 1 bis 999.999.999 */
#ifdef __ALPHA
         pz =  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         }
         else{
            pz = m10h_digits[0][(unsigned int)(kto[0]-'0')]
               + m10h_digits[3][(unsigned int)(kto[1]-'0')]
               + m10h_digits[2][(unsigned int)(kto[2]-'0')]
               + m10h_digits[1][(unsigned int)(kto[3]-'0')]
               + m10h_digits[0][(unsigned int)(kto[4]-'0')]
               + m10h_digits[3][(unsigned int)(kto[5]-'0')]
               + m10h_digits[2][(unsigned int)(kto[6]-'0')]
               + m10h_digits[1][(unsigned int)(kto[7]-'0')]
               + m10h_digits[0][(unsigned int)(kto[8]-'0')];
            MOD_10_80;   /* pz%=10 */
         }
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 28 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 28                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8.                        #
 * # Innerhalb der 10stelligen Kontonummer ist die 8. Stelle die        #
 * # Prüfziffer. Die 9. und 10. Stelle der Kontonummer sind             #
 * # Unterkontonummern, die nicht in die Prüfziffernberechnung          #
 * # einbezogen sind.                                                   #
 * # Jede Stelle der Konto-Stamm-Nummer wird mit einem festen           #
 * # Stellenfaktor (Reihenfolge 8, 7, 6, 5, 4, 3, 2) multipliziert.     #
 * # Die sich ergebenden Produkte werden addiert. Die aus der           #
 * # Addition erhaltene Summe wird durch 11 dividiert. Der Rest         #
 * # wird von 11 subtrahiert. Die Differenz wird der Konto-Stamm-       #
 * # Nummer als Prüfziffer beigefügt. Wird als Rest eine 0 oder         #
 * # eine 1 ermittelt, so lautet die Prüfziffer 0.                      #
 * ######################################################################
 */
      case 28:
#if DEBUG>0
         if(retvals){
            retvals->methode="28";
            retvals->pz_methode=28;
         }
#endif
         pz = (kto[0]-'0') * 8
            + (kto[1]-'0') * 7
            + (kto[2]-'0') * 6
            + (kto[3]-'0') * 5
            + (kto[4]-'0') * 4
            + (kto[5]-'0') * 3
            + (kto[6]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX8;
            /* evl. wurde eine Unterkontonummer weggelassen => nur 8-stellige
             * Kontonummer; neuer Versuch mit den Stellen ab der 3. Stelle
             */
         if(kto_len==8){
            pz = (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else
            return FALSE;


/*  Berechnung nach der Methode 29 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 29                        #
 * ######################################################################
 * # Modulus 10, Iterierte Transformation.                              #
 * # Die einzelnen Ziffern der Kontonummer werden über eine Tabelle     #
 * # in andere Werte transformiert. Jeder einzelnen Stelle der          #
 * # Kontonummer ist hierzu eine der Zeilen 1 bis 4 der Transforma-     #
 * # tionstabelle fest zugeordnet. Die Transformationswerte werden      #
 * # addiert. Die Einerstelle der Summe wird von 10 subtrahiert.        #
 * # Das Ergebnis ist die Prüfziffer. Ist das Ergebnis = 10, ist        #
 * # die Prüfziffer = 0.                                                #
 * # Transformationstabelle:                                            #
 * #    Ziffer    0 1 2 3 4 5 6 7 8 9                                   #
 * #    Ziffer 1  0 1 5 9 3 7 4 8 2 6                                   #
 * #    Ziffer 2  0 1 7 6 9 8 3 2 5 4                                   #
 * #    Ziffer 3  0 1 8 4 6 2 9 5 7 3                                   #
 * #    Ziffer 4  0 1 2 3 4 5 6 7 8 9                                   #
 * ######################################################################
 */
      case 29:
#if DEBUG>0
         if(retvals){
            retvals->methode="29";
            retvals->pz_methode=29;
         }
#endif
         pz = m10h_digits[0][(unsigned int)(kto[0]-'0')]
            + m10h_digits[3][(unsigned int)(kto[1]-'0')]
            + m10h_digits[2][(unsigned int)(kto[2]-'0')]
            + m10h_digits[1][(unsigned int)(kto[3]-'0')]
            + m10h_digits[0][(unsigned int)(kto[4]-'0')]
            + m10h_digits[3][(unsigned int)(kto[5]-'0')]
            + m10h_digits[2][(unsigned int)(kto[6]-'0')]
            + m10h_digits[1][(unsigned int)(kto[7]-'0')]
            + m10h_digits[0][(unsigned int)(kto[8]-'0')];
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnungsmethoden 30 bis 39 +§§§3
   Berechnung nach der Methode 30 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 30                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 0, 0, 0, 0, 1, 2, 1, 2.                  #
 * # Die letzte Stelle ist per Definition die Prüfziffer. Die           #
 * # einzelnen Stellen der Kontonummer sind ab der ersten Stelle von    #
 * # links nach rechts mit den Ziffern 2, 0, 0, 0, 0, 1, 2, 1, 2 zu     #
 * # multiplizieren. Die jeweiligen Produkte werden addiert (ohne       #
 * # Quersummenbildung). Die weitere Berechnung erfolgt wie bei         #
 * # Verfahren 00.                                                      #
 * ######################################################################
 */
      case 30:
#if DEBUG>0
         if(retvals){
            retvals->methode="30";
            retvals->pz_methode=30;
         }
#endif
         pz = (kto[0]-'0') * 2
            + (kto[5]-'0')
            + (kto[6]-'0') * 2
            + (kto[7]-'0')
            + (kto[8]-'0') * 2;

         MOD_10_40;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 31 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 31                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 9, 8, 7, 6, 5, 4, 3, 2, 1                   #
 * # Die Kontonummer ist 10-stellig. Die Stellen 1 bis 9 der            #
 * # Kontonummer sind von rechts nach links mit den Ziffern 9,          #
 * # 8, 7, 6, 5, 4, 3, 2, 1 zu multiplizieren. Die jeweiligen Produkte  #
 * # werden addiert. Die Summe ist durch 11 zu dividieren. Der          #
 * # verbleibende Rest ist die Prüfziffer. Verbleibt nach der           #
 * # Division durch 11 kein Rest, ist die Prüfziffer 0. Ergibt sich ein #
 * # Rest 10, ist die Kontonummer falsch.Die Prüfziffer  befindet sich  #
 * # in der 10. Stelle der Kontonummer.                                 #
 * ######################################################################
 */
      case 31:
#if DEBUG>0
         if(retvals){
            retvals->methode="31";
            retvals->pz_methode=31;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 2
            + (kto[2]-'0') * 3
            + (kto[3]-'0') * 4
            + (kto[4]-'0') * 5
            + (kto[5]-'0') * 6
            + (kto[6]-'0') * 7
            + (kto[7]-'0') * 8
            + (kto[8]-'0') * 9;

         MOD_11_352;   /* pz%=11 */
         if(pz==10){
            pz= *(kto+9)+1;
            return INVALID_KTO;
         }
         CHECK_PZ10;

/*  Berechnung nach der Methode 32 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 32                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7.                           #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 4 bis 9 angewendet. Die Gewichtung ist             #
 * # 2, 3, 4, 5, 6, 7. Die genannten Stellen werden von rechts          #
 * # nach links mit diesen Faktoren multipliziert. Die restliche        #
 * # Berechnung und mögliche Ergebnisse entsprechen dem Verfahren 06.   #
 * ######################################################################
 */
      case 32:
#if DEBUG>0
         if(retvals){
            retvals->methode="32";
            retvals->pz_methode=32;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 33 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 33                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6.                              #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 5 bis 9 angewendet. Die Gewichtung ist             #
 * # 2, 3, 4, 5, 6. Die genannten Stellen werden von rechts             #
 * # nach links mit diesen Faktoren multipliziert. Die restliche        #
 * # Berechnung und mögliche Ergebnisse entsprechen dem Verfahren 06.   #
 * ######################################################################
 */
      case 33:
#if DEBUG>0
         if(retvals){
            retvals->methode="33";
            retvals->pz_methode=33;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 34 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 34                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 4, 8, 5, A, 9, 7.                        #
 * # Die Kontonummer ist 10-stellig. Es wird das Berechnungsverfahren   #
 * # 28 mit modifizierter Gewichtung angewendet. Die Gewichtung         #
 * # lautet: 2, 4, 8, 5, A, 9, 7. Dabei steht der Buchstabe A für       #
 * # den Wert 10.                                                       #
 * ######################################################################
 */
      case 34:
#if DEBUG>0
         if(retvals){
            retvals->methode="34";
            retvals->pz_methode=34;
         }
#endif
         pz = (kto[0]-'0') * 7
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 10
            + (kto[3]-'0') * 5
            + (kto[4]-'0') * 8
            + (kto[5]-'0') * 4
            + (kto[6]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX8;

            /* evl. wurde eine Unterkontonummer weggelassen => nur 8-stellige
             * Kontonummer; neuer Versuch mit den Stellen ab der 3. Stelle
             */
         if(kto_len==8){
            pz = (kto[2]-'0') * 7
               + (kto[3]-'0') * 9
               + (kto[4]-'0') * 10
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 8
               + (kto[7]-'0') * 4
               + (kto[8]-'0') * 2;

            MOD_11_352;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else
            return FALSE;

/*  Berechnung nach der Methode 35 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 35                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10                  #
 * # Die Kontonummer ist ggf. durch linksbündige Nullenauffüllung       #
 * # 10-stellig darzustellen. Die 10. Stelle der Kontonummer ist die    #
 * # Prüfziffer. Die Stellen 1 bis 9 der Kontonummer werden von         #
 * # rechts nach links mit den Ziffern 2, 3, 4, ff. multipliziert. Die  #
 * # jeweiligen Produkte werden addiert. Die Summe der Produkte         #
 * # ist durch 11 zu dividieren. Der verbleibende Rest ist die          #
 * # Prüfziffer. Sollte jedoch der Rest 10 ergeben, so ist die          #
 * # Kontonummer unabhängig vom eigentlichen Berechnungsergebnis        #
 * # richtig, wenn die Ziffern an 10. und 9. Stelle identisch           #
 * # sind.                                                              #
 * ######################################################################
 */
      case 35:
#if DEBUG>0
         if(retvals){
            retvals->methode="35";
            retvals->pz_methode=35;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz==10){
            if(*(kto+8)== *(kto+9)){
               pz= *(kto+9)-'0';
               return OK;
            }
            else
               return INVALID_KTO;
         }
         CHECK_PZ10;

/*  Berechnung nach der Methode 36 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 36                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 4, 8, 5.                                 #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 6 bis 9 angewendet. Die Gewichtung ist             #
 * # 2, 4, 8, 5. Die genannten Stellen werden von rechts nach links     #
 * # mit diesen Faktoren multipliziert. Die restliche Berechnung        #
 * # und mögliche Ergebnisse entsprechen dem Verfahren 06.              #
 * ######################################################################
 */
      case 36:
#if DEBUG>0
         if(retvals){
            retvals->methode="36";
            retvals->pz_methode=36;
         }
#endif
         pz = (kto[5]-'0') * 5
            + (kto[6]-'0') * 8
            + (kto[7]-'0') * 4
            + (kto[8]-'0') * 2;

         MOD_11_88;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 37 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 37                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 4, 8, 5, A.                              #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 5 bis 9 angewendet. Die Gewichtung ist             #
 * # 2, 4, 8, 5, A. Dabei steht der Buchstabe A für den                 #
 * # Wert 10. Die genannten Stellen werden von rechts nach links        #
 * # mit diesen Faktoren multipliziert. Die restliche Berechnung        #
 * # und mögliche Ergebnisse entsprechen dem Verfahren 06.              #
 * ######################################################################
 */
      case 37:
#if DEBUG>0
         if(retvals){
            retvals->methode="37";
            retvals->pz_methode=37;
         }
#endif
         pz = (kto[4]-'0') * 10
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 8
            + (kto[7]-'0') * 4
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 38 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 38                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 4, 8, 5, A, 9.                           #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 4 bis 9 angewendet. Die Gewichtung ist             #
 * # 2, 4, 8, 5, A, 9. Dabei steht der Buchstabe A für den              #
 * # Wert 10. Die genannten Stellen werden von rechts nach links        #
 * # mit diesen Faktoren multipliziert. Die restliche Berechnung        #
 * # und mögliche Ergebnisse entsprechen dem Verfahren 06.              #
 * ######################################################################
 */
      case 38:
#if DEBUG>0
         if(retvals){
            retvals->methode="38";
            retvals->pz_methode=38;
         }
#endif
         pz = (kto[3]-'0') * 9
            + (kto[4]-'0') * 10
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 8
            + (kto[7]-'0') * 4
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 39 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 39                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 4, 8, 5, A, 9, 7.                        #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 3 bis 9 angewendet. Die Gewichtung ist             #
 * # 2, 4, 8, 5, A, 9, 7. Dabei steht der Buchstabe A für den           #
 * # Wert 10. Die genannten Stellen werden von rechts nach links        #
 * # mit diesen Faktoren multipliziert. Die restliche Berechnung        #
 * # und mögliche Ergebnisse entsprechen dem Verfahren 06.              #
 * ######################################################################
 */
      case 39:
#if DEBUG>0
         if(retvals){
            retvals->methode="39";
            retvals->pz_methode=39;
         }
#endif
         pz = (kto[2]-'0') * 7
            + (kto[3]-'0') * 9
            + (kto[4]-'0') * 10
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 8
            + (kto[7]-'0') * 4
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/* Berechnungsmethoden 40 bis 49 +§§§3
   Berechnung nach der Methode 40 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 40                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 4, 8, 5, A, 9, 7, 3, 6.                  #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 1 bis 9 angewendet. Die Gewichtung ist             #
 * # 2, 4, 8, 5, A, 9, 7, 3, 6. Dabei steht der Buchstabe A für den     #
 * # Wert 10. Die genannten Stellen werden von rechts nach links        #
 * # mit diesen Faktoren multipliziert. Die restliche Berechnung        #
 * # und mögliche Ergebnisse entsprechen dem Verfahren 06.              #
 * ######################################################################
 */
      case 40:
#if DEBUG>0
         if(retvals){
            retvals->methode="40";
            retvals->pz_methode=40;
         }
#endif
         pz = (kto[0]-'0') * 6
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 7
            + (kto[3]-'0') * 9
            + (kto[4]-'0') * 10
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 8
            + (kto[7]-'0') * 4
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 41 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 41                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2 (modifiziert)     #
 * # Die Berechnung erfolgt wie bei Verfahren 00                        #
 * # Ausnahme:                                                          #
 * # Ist die 4. Stelle der Kontonummer (von links) = 9, so werden       #
 * # die Stellen 1 bis 3 nicht in die Prüfzifferberechnung einbezogen.  #
 * ######################################################################
 */
      case 41:
#if DEBUG>0
         if(retvals){
            retvals->methode="41";
            retvals->pz_methode=41;
         }
#endif
         if(*(kto+3)=='9'){
#ifdef __ALPHA
            pz =  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

            pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
         }
         else{
#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
         }
         pz=pz%10;
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 42 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 42                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9.                     #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 2 bis 9 angewendet. Die Gewichtung ist             #
 * # 2, 3, 4, 5, 6, 7, 8, 9. Die genannten Stellen werden von           #
 * # rechts nach links mit diesen Faktoren multipliziert. Die           #
 * # restliche Berechnung und mögliche Ergebnisse entsprechen           #
 * # dem Verfahren 06.                                                  #
 * ######################################################################
 */
      case 42:
#if DEBUG>0
         if(retvals){
            retvals->methode="42";
            retvals->pz_methode=42;
         }
#endif
         pz = (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 43 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 43                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 1, 2, 3, 4, 5, 6, 7, 8, 9.                  #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 10 der Kontonummer ist         #
 * # per Definition die Prüfziffer.                                     #
 * # Das Verfahren wird auf die Stellen 1 bis 9 angewendet.             #
 * # Die genannten Stellen werden von rechts nach links                 #
 * # mit den Gewichtungsfaktoren multipliziert. Die Summe der           #
 * # Produkte wird durch den Wert 10 dividiert. Der Rest der            #
 * # Division wird vom Divisor subtrahiert. Die Differenz               #
 * # ist die Prüfziffer. Ergibt die Berechnung eine Differenz           #
 * # von 10, lautet die Prüfziffer 0.                                   #
 * ######################################################################
 */
      case 43:
#if DEBUG>0
         if(retvals){
            retvals->methode="43";
            retvals->pz_methode=43;
         }
#endif
         pz = (kto[0]-'0') * 9
            + (kto[1]-'0') * 8
            + (kto[2]-'0') * 7
            + (kto[3]-'0') * 6
            + (kto[4]-'0') * 5
            + (kto[5]-'0') * 4
            + (kto[6]-'0') * 3
            + (kto[7]-'0') * 2
            + (kto[8]-'0');

         MOD_10_320;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 44 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 44                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 4, 8, 5, A, 0, 0, 0, 0  (A = 10)         #
 * #                                                                    #
 * # Die Berechnung erfolgt wie bei Verfahren 33.                       #
 * # Stellennr.:    1 2 3 4 5 6 7 8 9 10                                #
 * # Kontonr.:      x x x x x x x x x P                                 #
 * # Gewichtung:    0 0 0 0 A 5 8 4 2    (A = 10)                       #
 * ######################################################################
 */
      case 44:
#if DEBUG>0
         if(retvals){
            retvals->methode="44";
            retvals->pz_methode=44;
         }
#endif
         pz = (kto[4]-'0') * 10
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 8
            + (kto[7]-'0') * 4
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 45 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 45                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Berechnung erfolgt wie bei Verfahren 00                        #
 * # Ausnahme:                                                          #
 * # Kontonummern, die an Stelle 1 (von links) eine 0 enthalten,        #
 * # und Kontonummern, die an Stelle 5 eine 1 enthalten,                #
 * # beinhalten keine Prüfziffer.                                       #
 * # Testkontonummern:                                                  #
 * # 3545343232, 4013410024                                             #
 * # Keine Prüfziffer enthalten:                                        #
 * # 0994681254, 0000012340 (da 1. Stelle = 0)                          #
 * # 1000199999, 0100114240 (da 5. Stelle = 1)                          #
 * ######################################################################
 */
      case 45:
#if DEBUG>0
         if(retvals){
            retvals->methode="45";
            retvals->pz_methode=45;
         }
#endif
         if(*kto=='0' || *(kto+4)=='1'){
#if DEBUG>0
            pz= *(kto+9)-'0';
#endif
            return OK_NO_CHK;
         }
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 46 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 46                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6.                              #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 8 der Kontonummer ist          #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 3 bis 7 angewendet. Die Gewichtung ist             #
 * # 2, 3, 4, 5, 6. Die genannten Stellen werden von                    #
 * # rechts nach links mit diesen Faktoren multipliziert. Die           #
 * # restliche Berechnung und mögliche Ergebnisse entsprechen           #
 * # dem Verfahren 06.                                                  #
 * ######################################################################
 */
      case 46:
#if DEBUG>0
         if(retvals){
            retvals->methode="46";
            retvals->pz_methode=46;
         }
#endif
         pz = (kto[2]-'0') * 6
            + (kto[3]-'0') * 5
            + (kto[4]-'0') * 4
            + (kto[5]-'0') * 3
            + (kto[6]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ8;

/*  Berechnung nach der Methode 47 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 47                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6.                              #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 9 der Kontonummer ist          #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 4 bis 8 angewendet. Die Gewichtung ist             #
 * # 2, 3, 4, 5, 6. Die genannten Stellen werden von                    #
 * # rechts nach links mit diesen Faktoren multipliziert. Die           #
 * # restliche Berechnung und mögliche Ergebnisse entsprechen           #
 * # dem Verfahren 06.                                                  #
 * ######################################################################
 */
      case 47:
#if DEBUG>0
         if(retvals){
            retvals->methode="47";
            retvals->pz_methode=47;
         }
#endif
         pz = (kto[3]-'0') * 6
            + (kto[4]-'0') * 5
            + (kto[5]-'0') * 4
            + (kto[6]-'0') * 3
            + (kto[7]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ9;

/*  Berechnung nach der Methode 48 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 48                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7.                           #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 9 der Kontonummer ist          #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 3 bis 8 angewendet. Die Gewichtung ist             #
 * # 2, 3, 4, 5, 6, 7. Die genannten Stellen werden von                 #
 * # rechts nach links mit diesen Faktoren multipliziert. Die           #
 * # restliche Berechnung und mögliche Ergebnisse entsprechen           #
 * # dem Verfahren 06.                                                  #
 * ######################################################################
 */
      case 48:
#if DEBUG>0
         if(retvals){
            retvals->methode="48";
            retvals->pz_methode=48;
         }
#endif
         pz = (kto[2]-'0') * 7
            + (kto[3]-'0') * 6
            + (kto[4]-'0') * 5
            + (kto[5]-'0') * 4
            + (kto[6]-'0') * 3
            + (kto[7]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ9;

/*  Berechnung nach der Methode 49 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 49                        #
 * ######################################################################
 * # Variante 1                                                         #
 * # Die Prüfzifferberechnung ist nach Kennziffer 00                    #
 * # durchzuführen. Führt die Berechnung nach Variante 1 zu             #
 * # einem Prüfzifferfehler, so ist die Berechnung nach                 #
 * # Variante 2 vorzunehmen.                                            #
 * #                                                                    #
 * # Variante 2                                                         #
 * # Die Prüfzifferberechnung ist nach Kennziffer 01                    #
 * # durchzuführen.                                                     #
 * ######################################################################
 */
      case 49:
#if DEBUG>0
      case 1049:
         if(retvals){
            retvals->methode="49a";
            retvals->pz_methode=1049;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

#if DEBUG>0
      case 2049:
         if(retvals){
            retvals->methode="49b";
            retvals->pz_methode=2049;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 7
            + (kto[2]-'0') * 3
            + (kto[3]-'0')
            + (kto[4]-'0') * 7
            + (kto[5]-'0') * 3
            + (kto[6]-'0')
            + (kto[7]-'0') * 7
            + (kto[8]-'0') * 3;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnungsmethoden 50 bis 59 +§§§3
   Berechnung nach der Methode 50 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 50                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7.                           #
 * # Die Kontonummer ist 10-stellig. Die einzelnen Stellen der          #
 * # Kontonummer werden von links nach rechts aufsteigend von           #
 * # 1 bis 10 durchnumeriert. Die Stelle 7 der Kontonummer ist          #
 * # per Definition die Prüfziffer.                                     #
 * # Es wird das Berechnungsverfahren 06 in modifizierter Form          #
 * # auf die Stellen 1 bis 6 angewendet. Die Gewichtung ist             #
 * # 2, 3, 4, 5, 6, 7. Die genannten Stellen werden von                 #
 * # rechts nach links mit diesen Faktoren multipliziert. Die           #
 * # restliche Berechnung und mögliche Ergebnisse entsprechen           #
 * # dem Verfahren 06.                                                  #
 * # Ergibt die erste Berechnung einen Prüfziffernfehler, wird          #
 * # empfohlen, die Prüfziffernberechnung ein zweites Mal durch-        #
 * # zuführen und dabei die "gedachte" Unternummer 000 an die           #
 * # Stellen 8 bis 10 zu setzen und die vorhandene Kontonummer          #
 * # vorher um drei Stellen nach links zu verschieben                   #
 * ######################################################################
 */
      case 50:
#if DEBUG>0
      case 1050:
         if(retvals){
            retvals->methode="50a";
            retvals->pz_methode=1050;
         }
#endif
         pz = (kto[0]-'0') * 7
            + (kto[1]-'0') * 6
            + (kto[2]-'0') * 5
            + (kto[3]-'0') * 4
            + (kto[4]-'0') * 3
            + (kto[5]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX7;

#if DEBUG>0
      case 2050:
         if(retvals){
            retvals->methode="50b";
            retvals->pz_methode=2050;
         }
#endif
            /* es ist eine reale Kontonummer bekannt, bei der rechts nur eine
             * Null weggelassen wurde; daher wird die Berechnung für die
             * Methode 50b leicht modifiziert, so daß eine, zwei oder drei
             * Stellen der Unterkontonummer 000 weggelassen werden können.
             */
         if(kto[0]=='0' && kto[1]=='0' && kto[2]=='0'){
            pz = (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else if(kto[0]=='0' && kto[1]=='0' && kto[9]=='0'){
            pz = (kto[2]-'0') * 7
               + (kto[3]-'0') * 6
               + (kto[4]-'0') * 5
               + (kto[5]-'0') * 4
               + (kto[6]-'0') * 3
               + (kto[7]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ9;
         }
         else if(kto[0]=='0' && kto[8]=='0' && kto[9]=='0'){
            pz = (kto[1]-'0') * 7
               + (kto[2]-'0') * 6
               + (kto[3]-'0') * 5
               + (kto[4]-'0') * 4
               + (kto[5]-'0') * 3
               + (kto[6]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ8;
         }
#if DEBUG>0
         else{   /* bei DEBUG wurde evl. direkt die Methode angesprungen; daher mit 50a testen */
            if(retvals){
               retvals->methode="50a";
               retvals->pz_methode=1050;
            }
            pz = (kto[0]-'0') * 7
               + (kto[1]-'0') * 6
               + (kto[2]-'0') * 5
               + (kto[3]-'0') * 4
               + (kto[4]-'0') * 3
               + (kto[5]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ7;
         }
#endif
         return FALSE;

/*  Berechnung nach der Methode 51 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 51 (geändert 3.6.13)      #
 * ######################################################################
 * # Die Kontonummer ist immer 10-stellig. Die für die Berechnung       #
 * # relevante Kundennummer (K) befindet sich bei den Methoden A und C  #
 * # in den Stellen 4 bis 9 der Kontonummer und bei den Methoden        #
 * # B + D in den Stellen 5 bis 9, die Prüfziffer in Stelle 10          #
 * # der Kontonummer.                                                   #
 * #                                                                    #
 * # Methode A:                                                         #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * # Die Berechnung und mögliche Ergebnisse entsprechen dem             #
 * # Verfahren 06.                                                      #
 * # Stellennr.:    1 2 3 4 5 6 7 8 9 A (A = 10)                        #
 * # Kontonr.:      x x x K K K K K K P                                 #
 * # Gewichtung:          7 6 5 4 3 2                                   #
 * #                                                                    #
 * # Ergibt die Berechnung der Prüfziffer nach der Methode A            #
 * # einen Prüfzifferfehler, ist eine weitere Berechnung mit der        #
 * # Methode B vorzunehmen.                                             #
 * #                                                                    #
 * # Methode B:                                                         #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6                               #
 * # Die Berechnung und mögliche Ergebnisse entsprechen dem             #
 * # Verfahren 33.                                                      #
 * # Stellennr.:    1 2 3 4 5 6 7 8 9 A (A = 10)                        #
 * # Kontonr.:      x x x x K K K K K P                                 #
 * # Gewichtung:            6 5 4 3 2                                   #
 * #                                                                    #
 * # Ergibt auch die Berechnung der Prüfziffer nach Methode B           #
 * # einen Prüfzifferfehler, ist eine weitere Berechnung mit der        #
 * # Methode C vorzunehmen.                                             #
 * #                                                                    #
 * # Methode C:                                                         #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1                            #
 * # Die Berechnung und die möglichen Ergebnisse entsprechen            #
 * # dem Verfahren 00; es ist jedoch zu beachten, dass nur die          #
 * # Stellen 4 bis 9 in das Prüfzifferberechnungsverfahren              #
 * # einbezogen werden                                                  #
 * # Stellennr.:    1 2 3 4 5 6 7 8 9 A (A = 10)                        #
 * # Kontonr.:      x x x K K K K K K P                                 #
 * # Gewichtung:          1 2 1 2 1 2                                   #
 * #                                                                    #
 * # Ergibt auch die Berechnung der Prüfziffer nach Methode C           #
 * # einen Prüfzifferfehler, ist eine weitere Berechnung mit der        #
 * # Methode D vorzunehmen.                                             #
 * #                                                                    #
 * # Methode D:                                                         #
 * # Kontonummern, die bis zur Methode D gelangen und in der 10.        #
 * # Stelle eine 7, 8 oder 9 haben, sind ungültig.                      #
 * # Modulus 7, Gewichtung 2, 3, 4, 5, 6                                #
 * # Das Berechnungsverfahren entspricht Methode B. Die Summe der       #
 * # Produkte ist jedoch durch 7 zu dividieren. Der verbleibende        #
 * # Rest wird vom Divisor (7) subtrahiert. Das Ergebnis ist die        #
 * # Prüfziffer. Verbleibt kein Rest, ist die Prüfziffer 0.             #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist nach linksbündiger Auffüllung mit Nullen auf 10 Stellen die    #
 * # 3. Stelle der Kontonummer = 9 (Sachkonten), so erfolgt die         #
 * # Berechnung wie folgt:                                              #
 * #                                                                    #
 * # Variante 1 zur Ausnahme                                            #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8                         #
 * # Die für die Berechnung relevanten Stellen 3 bis 9 werden von       #
 * # rechts nach links mit den Ziffern 2, 3, 4, 5, 6, 7, 8              #
 * # multipliziert. Die Produkte werden addiert. Die Summe ist durch 11 #
 * # zu dividieren. Der verbleibende Rest wird vom Divisor (11)         #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Ergibt sich als Rest #
 * # 1 oder 0, ist die Prüfziffer 0.                                    #
 * #                                                                    #
 * # Stellennr.:   1 2 3 4 5 6 7 8 9 A (A=10)                           #
 * # Kontonr.;     x x 9 x x x x x x P                                  #
 * # Gewichtung:       8 7 6 5 4 3 2                                    #
 * #                                                                    #
 * # Führt die Variante 1 zur Ausnahme zu einem Prüfzifferfehler, ist   #
 * # eine weitere Berechnung nach der Variante 2 vorzunehmen.           #
 * #                                                                    #
 * # Variante 2 zur Ausnahme                                            #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10                  #
 * # Berechnung und Ergebnisse entsprechen der Variante 1 zur Ausnahme. #
 * ######################################################################
 */

      case 51:
         if(*(kto+2)=='9'){   /* Ausnahme */

            /* Variante 1 */
#if DEBUG>0
      case 5051:
         if(retvals){
            retvals->methode="51e";
            retvals->pz_methode=5051;
         }
#endif
            pz =         9 * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

            /* Variante 2 */
#if DEBUG>0
      case 6051:
         if(retvals){
            retvals->methode="51f";
            retvals->pz_methode=6051;
         }
#endif
               pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               +            9 * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

               MOD_11_352;   /* pz%=11 */
               if(pz<=1)
                  pz=0;
               else
                  pz=11-pz;
               CHECK_PZ10;
            }

            /* Methode A */
#if DEBUG>0
      case 1051:
         if(retvals){
            retvals->methode="51a";
            retvals->pz_methode=1051;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode B */
#if DEBUG>0
      case 2051:
         if(retvals){
            retvals->methode="51b";
            retvals->pz_methode=2051;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode C */
#if DEBUG>0
      case 3051:
         if(retvals){
            retvals->methode="51c";
            retvals->pz_methode=3051;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Methode D */

 /* In der Beschreibung der Bundesbank für Methode 51d ist eine falsche Test-Kontonummer angegeben:
  * statt 101345073 muß sie 101345075 lauten:
  *
  *   Kontonummer: 0   1   0   1   3   4   5   0   7   3            
  *   Gewicht:     0   0   0   0   6   5   4   3   2  (P)          
  *   Produkte:    0   0   0   0  18  20  20   0  14               
  *   Summe der Produkte: 72                                       
  *   72 Modulo 7 = 2                                              
  *   Differenz/Prüfziffer: 7-2 = 5                                
  *
  */
#if DEBUG>0
      case 4051:
         if(retvals){
            retvals->methode="51d";
            retvals->pz_methode=4051;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;
         MOD_7_112;   /* pz%=7 */
         if(pz)pz=7-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 52 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 52                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 4, 8, 5, 10, 9, 7, 3, 6, 1, 2, 4.        #
 * # Zur Berechnung der Prüfziffer muß zunächst aus der angegebenen     #
 * # achtstelligen Kontonummer die zugehörige Kontonummer des ESER-     #
 * # Altsystems (maximal 12stellig) ermittelt werden. Die einzelnen     #
 * # Stellen dieser Alt-Kontonummer sind von rechts nach links mit      #
 * # den Ziffern 2, 4, 8, 5, 10, 9, 7, 3, 6, 1, 2, 4 zu multipli-       #
 * # zieren. Dabei ist für die Prüfziffer, die sich immer an der        #
 * # 6. Stelle von links der Alt-Kontonummer befindet, 0 zu setzen.     #
 * # Die jeweiligen Produkte werden addiert und die Summe durch 11      #
 * # dividiert. Zum Divisionsrest (ggf. auch 0) ist das Gewicht         #
 * # oder ein Vielfaches des Gewichtes über der Prüfziffer zu           #
 * # addieren. Die Summe wird durch 11 dividiert; der Divisionsrest     #
 * # muß 10 lauten. Die Prüfziffer ist der verwendete Faktor des        #
 * # Gewichtes. Kann bei der Division kein Rest 10 erreicht werden,     #
 * # ist die Konto-Nr. nicht verwendbar.                                #
 * # Bildung der Konto-Nr. des ESER-Altsystems aus angegebener          #
 * # Bankleitzahl und Konto-Nr.: XXX5XXXX XPXXXXXX (P=Prüfziffer)       #
 * # Kontonummer des Altsystems: XXXX-XP-XXXXX (XXXXX = variable        #
 * # Länge, da evtl.vorlaufende Nullen eliminiert werden).              #
 * # Bei 10stelligen, mit 9 beginnenden Kontonummern ist die            #
 * # Prüfziffer nach Kennziffer 20 zu berechnen.                        #
 * ######################################################################
 */
      case 52:

            /* Berechnung nach Methode 20 */
#if DEBUG>0
      case 1052:
         if(retvals){
            retvals->methode="52a";
            retvals->pz_methode=1052;
         }
#endif
         if(*kto=='9'){
            pz = (kto[0]-'0') * 3
               + (kto[1]-'0') * 9
               + (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_352;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

               /* nur Prüfziffer angegeben; Test-BLZ einsetzen */
#if DEBUG>0
      case 2052:
         if(retvals){
            retvals->methode="52b";
            retvals->pz_methode=2052;
         }
#endif
         if(!x_blz){
            ok=OK_TEST_BLZ_USED;
            x_blz=(char*)"13051172";
         }
         else
            ok=OK;

            /* Generieren der Konto-Nr. des ESER-Altsystems */
         for(ptr=kto;*ptr=='0';ptr++);
         if(ptr>kto+2)return INVALID_KTO;
         kto_alt[0]=x_blz[4];
         kto_alt[1]=x_blz[5];
         kto_alt[2]=x_blz[6];
         kto_alt[3]=x_blz[7];
         kto_alt[4]= *ptr++;
         kto_alt[5]= *ptr++;
#if DEBUG>0
         if(retvals){
            retvals->pz_pos=(ptr-kto)+1;
            retvals->pz=kto_alt[5]-'0';
         }
#endif
         while(*ptr=='0' && *ptr)ptr++;
         for(dptr=kto_alt+6;(*dptr= *ptr++);dptr++);
            /* die Konto-Nr. des ESER-Altsystems darf maximal 12 Stellen haben */
         if((dptr-kto_alt)>12)return INVALID_KTO;
         p1=kto_alt[5];   /* Prüfziffer */
         kto_alt[5]='0';
         for(pz=0,ptr=dptr-1,i=0;ptr>=kto_alt;ptr--,i++)pz+=(*ptr-'0')*w52[i];
         kto_alt[5]=p1;
         pz=pz%11;
         p1=w52[i-6];

            /* passenden Faktor suchen */
         tmp=pz;
         for(i=0;i<10;i++){
            pz=tmp+p1*i;
            MOD_11_88;
            if(pz==10)break;
         }
         pz=i; /* Prüfziffer ist der verwendete Faktor des Gewichtes */
         INVALID_PZ10;
         if(*(kto_alt+5)-'0'==pz)
            return ok;
         else
            return FALSE;

/*  Berechnung nach der Methode 53 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 53                        #
 * ######################################################################
 * # Analog Kennziffer 52, jedoch für neunstellige Kontonummern.        #
 * # Bildung der Kontonummern des ESER-Altsystems aus angegebener       #
 * # Bankleitzahl und angegebener neunstelliger Kontonummer:            #
 * # XXX5XXXX XTPXXXXXX (P=Prüfziffer)                                  #
 * # Kontonummer des Altsystems: XXTX-XP-XXXXX (XXXXX = variable        #
 * # Länge, da evtl.vorlaufende Nullen eliminiert werden).              #
 * # Die Ziffer T ersetzt die 3. Stelle von links der nach              #
 * # Kennziffer 52 gebildeten Kontonummer des ESER-Altsystems.          #
 * # Bei der Bildung der Kontonummer des ESER-Altsystems wird die       #
 * # Ziffer T nicht in den Kundennummernteil (7.-12. Stelle der         #
 * # Kontonummer) übernommen.                                           #
 * # Bei 10stelligen, mit 9 beginnenden Kontonummern ist die            #
 * # Prüfziffer nach Kennziffer 20 zu berechnen.                        #
 * ######################################################################
 */
      case 53:

            /* Berechnung nach Methode 20 */
         if(*kto=='9'){
#if DEBUG>0
      case 1053:
         if(retvals){
            retvals->methode="53a";
            retvals->pz_methode=1053;
         }
#endif
         pz = (kto[0]-'0') * 3
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

               /* nur Prüfziffer angegeben; Test-BLZ einsetzen */
#if DEBUG>0
      case 2053:
         if(retvals){
            retvals->methode="53b";
            retvals->pz_methode=2053;
         }
#endif
         if(!x_blz){
            ok=OK_TEST_BLZ_USED;
            x_blz=(char*)"16052072";
         }
         else
            ok=OK;

            /* Generieren der Konto-Nr. des ESER-Altsystems */
         for(ptr=kto;*ptr=='0';ptr++);
         if(*kto!='0' || *(kto+1)=='0'){  /* Kto-Nr. muß neunstellig sein */
#if DEBUG>0
            if(retvals)retvals->pz= -2;
#endif
            return INVALID_KTO;
         }
         kto_alt[0]=x_blz[4];
         kto_alt[1]=x_blz[5];
         kto_alt[2]=kto[2];         /* T-Ziffer */
         kto_alt[3]=x_blz[7];
         kto_alt[4]=kto[1];
         kto_alt[5]=kto[3];
         for(ptr=kto+4;*ptr=='0' && *ptr;ptr++);
         for(dptr=kto_alt+6;(*dptr= *ptr++);dptr++);
         p1=kto_alt[5];   /* Prüfziffer merken */
         kto_alt[5]='0';
         for(pz=0,ptr=kto_alt+strlen(kto_alt)-1,i=0;ptr>=kto_alt;ptr--,i++)
            pz+=(*ptr-'0')*w52[i];
         kto_alt[5]=p1;   /* Prüfziffer zurückschreiben */
         pz=pz%11;
         p1=w52[i-6];

            /* passenden Faktor suchen */
         tmp=pz;
         for(i=0;i<10;i++){
            pz=tmp+p1*i;
            MOD_11_88;
            if(pz==10)break;
         }
         pz=i; /* Prüfziffer ist der verwendete Faktor des Gewichtes */
#if DEBUG>0
         if(retvals)retvals->pz=pz; 
#endif
         INVALID_PZ10;
         if(*(kto_alt+5)-'0'==pz)
            return ok;
         else
            return FALSE;

/*  Berechnung nach der Methode 54 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 54                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2                         #
 * # Die Kontonummer ist 10-stellig, wobei die Stellen 1 u. 2           #
 * # generell mit 49 belegt sind. Die einzelnen Stellen der             #
 * # Kontonummer sind von rechts nach links mit den Ziffern 2, 3,       #
 * # 4, 5, 6, 7, 2 zu multiplizieren. Die jeweiligen Produkte werden    #
 * # addiert. Die Summe ist durch 11 zu dividieren. Der verbleibende    #
 * # Rest wird vom Divisor (11) subtrahiert. Das Ergebnis ist die       #
 * # Prüfziffer. Ergibt sich als Rest 0 oder 1, ist die Prüfziffer      #
 * # zweistellig und kann nicht verwendet werden. Die Kontonummer       #
 * # ist dann nicht verwendbar.                                         #
 * ######################################################################
 */
      case 54:
#if DEBUG>0
         if(retvals){
            retvals->methode="54";
            retvals->pz_methode=54;
         }
#endif
         if(*kto!='4' && *(kto+1)!='9')return INVALID_KTO;
         pz = (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         pz=11-pz;
         if(pz>9)return INVALID_KTO;
         CHECK_PZ10;

/*  Berechnung nach der Methode 55 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 55                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 7, 8 (modifiziert).    #
 * # Die Berechnung erfolgt wie bei Verfahren 06.                       #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach         #
 * # links mit den Ziffern 2, 3, 4, 5, 6, 7, 8, 7, 8 zu                 #
 * # multiplizieren. Die jeweiligen Produkte werden addiert.            #
 * # Die Summe ist durch 11 zu dividieren. Der verbleibende Rest        #
 * # wird vom Divisor (11) subtrahiert. Das Ergebnis ist die            #
 * # Prüfziffer. Verbleibt nach der Division durch 11 kein Rest,        #
 * # ist die Prüfziffer 0. Ergibt sich als Rest 1, entsteht bei         #
 * # der Subtraktion 11 - 1 = 10. Das Rechenergebnis ist                #
 * # nicht verwendbar und muß auf eine Stelle reduziert werden.         #
 * # Die linke Seite wird eliminiert, und nur die rechte Stelle         #
 * # (Null) findet als Prüfziffer Verwendung.                           #
 * ######################################################################
 */
      case 55:
#if DEBUG>0
         if(retvals){
            retvals->methode="55";
            retvals->pz_methode=55;
         }
#endif
         pz = (kto[0]-'0') * 8
            + (kto[1]-'0') * 7
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 56 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 56                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4.                  #
 * # Prüfziffer ist die letzte Stelle der Kontonummer.                  #
 * # Von rechts beginnend werden die einzelnen Ziffern der              #
 * # Kontonummer mit den Gewichten multipliziert. Die Produkte der      #
 * # Multiplikation werden addiert und diese Summe durch 11             #
 * # dividiert. Der Rest wird von 11 abgezogen, das Ergebnis ist        #
 * # die Prüfziffer, die an die Kontonummer angehängt wird.             #
 * # 1. Bei dem Ergebnis 10 oder 11 ist die Kontonummer ungültig.       #
 * # 2. Beginnt eine zehnstellige Kontonummer mit 9, so wird beim       #
 * # Ergebnis 10 die Prüfziffer 7 und beim Ergebnis 11 die              #
 * # Prüfziffer 8 gesetzt.                                              #
 * ######################################################################
 */
      case 56:
#if DEBUG>0
         if(retvals){
            retvals->methode="56";
            retvals->pz_methode=56;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         pz=11-pz;
         if(pz>9){
            if(*kto=='9'){
               if(pz==10)
                  pz=7;
               else
                  pz=8;
            }
            else
               return INVALID_KTO;
         }
         CHECK_PZ10;

/*  Berechnung nach der Methode 57 +§§§4 */
/*
 * ######################################################################
 * #    Berechnung nach der Methode 57 (geändert zum 09.09.2013)        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen. Die    #
 * # Berechnung der Prüfziffer und die möglichen Ergebnisse richten     #
 * # sich nach dem jeweils bei der entsprechenden Variante angegebenen  #
 * # Kontonummernkreis. Führt die Berechnung der Prüfziffer nach der    #
 * # vorgegebenen Variante zu einem Prüfzifferfehler, so ist die        #
 * # Kontonummer ungültig. Kontonummern, die mit 00 beginnen sind       #
 * # immer als falsch zu bewerten.                                      #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 1, 2, 1, 2, 1, 2, 1, 2, 1                   #
 * # Anzuwenden ist dieses Verfahren für Kontonummern, die mit den      #
 * # folgenden Zahlen beginnen:                                         #
 * #                                                                    #
 * # 51, 55, 61, 64, 65, 66, 70, 73 bis 82, 88, 94 und 95               #
 * # (Konten, die mit 74 beginnen, ab 9.9.2013; bis dahin werden diese  #
 * # mit Variante 2 berechnet)                                          #
 * #                                                                    #
 * # Die Stellen 1 bis 9 der Kontonummer sind von                       #
 * # links beginnend mit den Gewichten zu multiplizieren. Die 10.       #
 * # Stelle ist die Prüfziffer. Die Berechnung und mögliche Ergebnisse  #
 * # entsprechen der Methode 00.                                        #
 * #                                                                    #
 * # Ausnahme: Kontonummern, die mit den Zahlen 777777 oder 888888      #
 * # beginnen sind immer als richtig (= Methode 09; keine Prüfziffer-   #
 * # berechnung) zu bewerten.                                           #
 * #                                                                    #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 1, 2, 1, 2, 1, 2, 1, 2, 1                   #
 * # Anzuwenden ist dieses Verfahren für Kontonummern, die mit den      #
 * # folgenden Zahlen beginnen:                                         #
 * #                                                                    #
 * # 32 bis 39, 41 bis 49, 52, 53, 54, 56 bis 60, 62, 63, 67, 68, 69,   #
 * # 71, 72, 83 bis 87, 89, 90, 92, 93, 96, 97 und 98                   #
 * # (bis 9.9.2013 auch Konten, die mit 74 beginnen)                    #
 * #                                                                    #
 * # Die Stellen 1, 2, 4, 5, 6, 7, 8, 9 und 10 der Kontonummer sind     #
 * # von links beginnend mit den Gewichten zu multiplizieren. Die 3.    #
 * # Stelle ist die Prüfziffer. Die Berechnung und mögliche Ergebnisse  #
 * # entsprechen der Methode 00.                                        #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Für die Kontonummern, die mit den folgenden Zahlen beginnen gilt   #
 * # die Methode 09 (keine Prüfzifferberechnung):                       #
 * # 40, 50, 91 und 99                                                  #
 * #                                                                    #
 * # Variante 4:                                                        #
 * # Kontonummern die mit 01 bis 31 beginnen haben an der dritten bis   #
 * # vierten Stelle immer einen Wert zwischen 01 und 12 *und* an der    #
 * # siebten bis neunten Stelle immer einen Wert kleiner 500.           #
 * #                                                                    #
 * # Ausnahme: Die Kontonummer 0185125434 ist als richtig zu            #
 * # bewerten.                                                          #
 * ######################################################################
 */
      case 57:
#if DEBUG>0
         if(retvals){
            retvals->methode="57";
            retvals->pz_methode=57;
         }
#endif
#if DEBUG>0
      case 1057:  /* die Untermethoden werden in einem eigenen switch abgearbeitet, daher alle hier zusammen */
      case 2057:
      case 3057:
      case 4057:
         if(retvals){
            retvals->methode="57";
            retvals->pz_methode=57;
         }
#endif
            /* erstmal die Sonderfälle abhaken */
         if(!strncmp(kto,"777777",6) || !strncmp(kto,"888888",6)){
#if DEBUG>0
            if(retvals){
               retvals->methode="57a";
               retvals->pz_methode=1057;
            }
#endif
            return OK_NO_CHK;
         }
         if(!strcmp(kto,"0185125434")){
#if DEBUG>0
            if(retvals){
               retvals->methode="57d";
               retvals->pz_methode=4057;
            }
#endif
            return OK_NO_CHK;
         }

         tmp=(kto[0]-'0')*10+kto[1]-'0';  /* die ersten beiden Stellen als Integer holen */
         switch(tmp){
            case 51:
            case 55:
            case 61:
            case 64:
            case 65:
            case 66:
            case 70:
            case 73: 
            case 74: 
            case 75:
            case 76:
            case 77:
            case 78:
            case 79:
            case 80:
            case 81:
            case 82: 
            case 88: 
            case 94:
            case 95:  /* Variante 1 */
#if DEBUG>0
               if(retvals){
                  retvals->methode="57a";
                  retvals->pz_methode=1057;
               }
#endif
#ifdef __ALPHA
               pz =  (kto[0]-'0')
                  + ((kto[1]<'5') ? (kto[1]-'0')*2 : (kto[1]-'0')*2-9)
                  +  (kto[2]-'0')
                  + ((kto[3]<'5') ? (kto[3]-'0')*2 : (kto[3]-'0')*2-9)
                  +  (kto[4]-'0')
                  + ((kto[5]<'5') ? (kto[5]-'0')*2 : (kto[5]-'0')*2-9)
                  +  (kto[6]-'0')
                  + ((kto[7]<'5') ? (kto[7]-'0')*2 : (kto[7]-'0')*2-9)
                  +  (kto[8]-'0');
#else
               pz=(kto[0]-'0')+(kto[2]-'0')+(kto[4]-'0')+(kto[6]-'0')+(kto[8]-'0');
               if(kto[1]<'5')pz+=(kto[1]-'0')*2; else pz+=(kto[1]-'0')*2-9;
               if(kto[3]<'5')pz+=(kto[3]-'0')*2; else pz+=(kto[3]-'0')*2-9;
               if(kto[5]<'5')pz+=(kto[5]-'0')*2; else pz+=(kto[5]-'0')*2-9;
               if(kto[7]<'5')pz+=(kto[7]-'0')*2; else pz+=(kto[7]-'0')*2-9;
#endif
               MOD_10_80;   /* pz%=10 */
               if(pz)pz=10-pz;
               CHECK_PZ10;
               break;

            case 32:
            case 33:
            case 34:
            case 35:
            case 36:
            case 37:
            case 38:
            case 39:
            case 41:
            case 42:
            case 43:
            case 44:
            case 45:
            case 46:
            case 47:
            case 48:
            case 49:
            case 52:
            case 53:
            case 54:
            case 56:
            case 57:
            case 58:
            case 59:
            case 60:
            case 62:
            case 63:
            case 67:
            case 68:
            case 69:
            case 71:
            case 72:
            case 83:
            case 84:
            case 85:
            case 86:
            case 87:
            case 89:
            case 90:
            case 92:
            case 93:
            case 96:
            case 97:
            case 98:  /* Variante 2 */
#if DEBUG>0
               if(retvals){
                  retvals->methode="57b";
                  retvals->pz_methode=2057;
               }
#endif
#ifdef __ALPHA
               pz =  (kto[0]-'0')
                  + ((kto[1]<'5') ? (kto[1]-'0')*2 : (kto[1]-'0')*2-9)
                  +  (kto[3]-'0')
                  + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
                  +  (kto[5]-'0')
                  + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
                  +  (kto[7]-'0')
                  + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9)
                  +  (kto[9]-'0');
#else
               pz=(kto[0]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0')+(kto[9]-'0');
               if(kto[1]<'5')pz+=(kto[1]-'0')*2; else pz+=(kto[1]-'0')*2-9;
               if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
               if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
               if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
               MOD_10_80;   /* pz%=10 */
               if(pz)pz=10-pz;
               CHECK_PZ3;
               break;

            case 40:
            case 50:
            case 91:
            case 99:  /* Variante 3 */
#if DEBUG>0
               if(retvals){
                  retvals->methode="57c";
                  retvals->pz_methode=3057;
               }
#endif
               return OK_NO_CHK;

            default:   /* Variante 4 */
#if DEBUG>0
               if(retvals){
                  retvals->methode="57d";
                  retvals->pz_methode=4057;
               }
#endif
               if(tmp==0)return INVALID_KTO; /* Kontonummern müssen mit 01 bis 31 beginnen */
               tmp=(kto[2]-'0')*10+kto[3]-'0';
               if(tmp==0 || tmp>12)return INVALID_KTO;
               tmp=(kto[6]-'0')*100+(kto[7]-'0')*10+kto[8]-'0';
               if(tmp>=500)return INVALID_KTO;

                 /* Es ist kein eigentliches Berechnungsverfahren angegeben, aber die
                  * Kontonummer entspricht den Vorgaben. Daher wird einfach OK_NO_CHK
                  * zurückgegeben (es gibt ja keine Prüfziffer)
                  */
               return OK_NO_CHK;
         }


/*  Berechnung nach der Methode 58 +§§§4 */
/*
 * ######################################################################
 * #   Berechnung nach der Methode 58 (geändert zum 4.3.2002)           #
 * ######################################################################
 * # Die Kontonummer (mindestens 6-stellig) ist durch linksbündige      #
 * # Nullenauffüllung 10-stellig darzustellen. Danach ist die 10.       #
 * # Stelle die Prüfziffer. Die Stellen 5 bis 9 werden von rechts nach  #
 * # links mit den Ziffern 2, 3, 4, 5, 6 multipliziert. Die restliche   #
 * # Berechnung und die Ergebnisse entsprechen dem Verfahren 02.        #
 * #                                                                    #
 * # Ergibt die Division einen Rest von 0, so ist die Prüfziffer = 0.   #
 * # Bei einem Rest von 1 ist die Kontonummer falsch.                   #
 * ######################################################################
 */

      case 58:
#if DEBUG>0
         if(retvals){
            retvals->methode="58";
            retvals->pz_methode=58;
         }
#endif
         if(kto[0]=='0' && kto[1]=='0' && kto[2]=='0' && kto[3]=='0' && kto[4]=='0')
            return INVALID_KTO;
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz)pz=11-pz;
         INVALID_PZ10;
         CHECK_PZ10;

/*  Berechnung nach der Methode 59 +§§§4 */
/*
 * ######################################################################
 * #    Berechnung nach der Methode 59 (geändert seit 3.12.2001)        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2.                  #
 * # Die Berechnung erfolgt wie bei Verfahren 00; es ist jedoch         #
 * # zu beachten, daß Kontonummern, die kleiner als 9-stellig sind,     #
 * # nicht in die Prüfziffernberechnung einbezogen werden.              #
 * ######################################################################
 */
      case 59:
#if DEBUG>0
         if(retvals){
            retvals->methode="59";
            retvals->pz_methode=59;
         }
#endif
         if(*kto=='0' && *(kto+1)=='0')return OK_NO_CHK;
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnungsmethoden 60 bis 69 +§§§3
   Berechnung nach der Methode 60 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 60                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2.                        #
 * # Die Berechnung erfolgt wie bei Verfahren 00. Es ist jedoch zu      #
 * # beachten, daß die zweistellige Unterkontonummer (Stellen 1 und     #
 * # 2) nicht in das Prüfziffernverfahren mit einbezogen werden darf.   #
 * # Die für die Berechnung relevante siebenstellige Grundnummer        #
 * # befindet sich in den Stellen 3 bis 9, die Prüfziffer in der        #
 * # Stelle 10.                                                         #
 * ######################################################################
 */
      case 60:
#if DEBUG>0
         if(retvals){
            retvals->methode="60";
            retvals->pz_methode=60;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 61 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 61                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2.                        #
 * # Darstellung der Kontonummer: B B B S S S S P A U (10-stellig).     #
 * # B = Betriebsstellennummer                                          #
 * # S = Stammnummer                                                    #
 * # P = Prüfziffer                                                     #
 * # A = Artziffer                                                      #
 * # U = Unternummer                                                    #
 * # Die Berechnung erfolgt wie bei Verfahren 00 über Betriebs-         #
 * # stellennummer und Stammnummer mit der Gewichtung 2, 1, 2, 1,       #
 * # 2, 1, 2.                                                           #
 * # Ist die Artziffer (neunte Stelle der Kontonummer) eine 8, so       #
 * # werden die neunte und zehnte Stelle der Kontonummer in die         #
 * # Prüfziffernermittlung einbezogen. Die Berechnung erfolgt dann      #
 * # über Betriebsstellennummer, Stammnummer, Artziffer und Unter-      #
 * # nummer mit der Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2.               #
 * ######################################################################
 */
      case 61:
         if(*(kto+8)=='8'){
#if DEBUG>0
      case 2061:
         if(retvals){
            retvals->methode="61b";
            retvals->pz_methode=2061;
         }
#endif
#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[8]-'0')
               + ((kto[9]<'5') ? (kto[9]-'0')*2 : (kto[9]-'0')*2-9);
#else

            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[8]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[9]<'5')pz+=(kto[9]-'0')*2; else pz+=(kto[9]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ8;
         }
         else{
#if DEBUG>0
      case 1061:
         if(retvals){
            retvals->methode="61a";
            retvals->pz_methode=1061;
         }
#endif
#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else
            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ8;
         }

/*  Berechnung nach der Methode 62 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 62                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2.                              #
 * # Die beiden ersten und die beiden letzten Stellen sind              #
 * # nicht zu berücksichtigen. Die Stellen drei bis sieben              #
 * # sind von rechts nach links mit den Ziffern 2, 1, 2, 1, 2           #
 * # zu multiplizieren. Aus zweistelligen Einzelergebnissen             #
 * # ist eine Quersumme zu bilden. Alle Ergebnisse sind dann            #
 * # zu addieren. Die Differenz zum nächsten Zehner ergibt die          #
 * # Prüfziffer auf Stelle acht. Ist die Differenz 10, ist die          #
 * # Prüfziffer 0.                                                      #
 * ######################################################################
 */
      case 62:
#if DEBUG>0
         if(retvals){
            retvals->methode="62";
            retvals->pz_methode=62;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else

         pz=(kto[3]-'0')+(kto[5]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif
         MOD_10_40;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ8;

/*  Berechnung nach der Methode 63 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 63                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1.                           #
 * # Die für die Berechnung relevante 6-stellige Grundnummer            #
 * # (Kundennummer) befindet sich in den Stellen 2-7, die Prüfziffer    #
 * # in Stelle 8 der Kontonummer. Die zweistellige Unterkontonummer     #
 * # (Stellen 9-10) ist nicht in das Prüfziffernverfahren einzu-        #
 * # beziehen. Die einzelnen Stellen der Grundnummer sind von rechts    #
 * # nach links mit den Ziffern 2, 1, 2, 1, 2, 1 zu multiplizieren.     #
 * # Die jeweiligen Produkte werden addiert, nachdem jeweils aus        #
 * # den zweistelligen Produkten die Quersumme gebildet wurde           #
 * # (z.B. Produkt 16 = Quersumme 7). Nach der Addition bleiben         #
 * # außer der Einerstelle alle anderen Stellen unberücksichtigt.       #
 * # Die Einerstelle wird von dem Wert 10 subtrahiert. Das Ergebnis     #
 * # ist die Prüfziffer (Stelle 8). Hat die Einerstelle den Wert 0,     #
 * # ist die Prüfziffer 0. Ausnahmen:                                   #
 * # Ist die Ziffer in Stelle 1 vor der sechsstelligen Grundnummer      #
 * # nicht 0, ist das Ergebnis als falsch zu werten.                    #
 * # Ist die Unterkontonummer 00, kann es vorkommen, daß sie auf        #
 * # den Zahlungsverkehrsbelegen nicht angegeben ist, die Kontonummer   #
 * # jedoch um führende Nullen ergänzt wurde. In diesem Fall sind       #
 * # z.B. die Stellen 1-3 000, die Prüfziffer ist an der Stelle 10.     #
 * ######################################################################
 */
      case 63:

      /* der Test auf evl. weggelassenes Unterkonto erfolgt nun am Anfang
       * der Methode, nicht mehr am Ende; dadurch werden einige bislang (wohl
       * irrtümlich) als korrekt angesehene Konten als falsch ausgegeben.
       * Die Beschreibung ist nicht eindeutig; scheinbar werden allerdings
       * öfters Unterkonten weggelassen, als daß führende Nullen (an dieser
       * Stelle, nicht allgemein bei den Banken ;-) ) auftreten (vielen Dank
       * an Th. Franz für den Hinweis).
       */
      if(*(kto+1)=='0' && *(kto+2)=='0'){ /* Unterkonto weggelassen */
#if DEBUG>0
      case 2063:
         if(retvals){
            retvals->methode="63b";
            retvals->pz_methode=2063;
         }
#endif
         if(*kto!='0')return INVALID_KTO;
#ifdef __ALPHA
         pz =   (kto[3]-'0')
            +  ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +   (kto[5]-'0')
            +  ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +   (kto[7]-'0')
            +  ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;
      }
#if DEBUG>0
      case 1063:
         if(retvals){
            retvals->methode="63a";
            retvals->pz_methode=1063;
         }
#endif
      if(*kto!='0')return INVALID_KTO;
#ifdef __ALPHA
         pz =   (kto[1]-'0')
            +  ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +   (kto[3]-'0')
            +  ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +   (kto[5]-'0')
            +  ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ8;

/*  Berechnung nach der Methode 64 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 64                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 9, 10, 5, 8, 4, 2.                          #
 * #  Die Kontonummer ist 10-stellig. Die für die Berechnung relevanten #
 * #  Stellen der Kontonummer befinden sich in den Stellen 1 bis 6 und  #
 * #  werden von links nach rechts mit den Ziffern 9, 10, 5, 8, 4, 2    #
 * #  multipliziert. Die weitere Berechnung und Ergebnisse entsprechen  #
 * #  dem Verfahren 06. Die Prüfziffer befindet sich in Stelle 7 der    #
 * #  Kontonummer.                                                      #
 * ######################################################################
 */
      case 64:
#if DEBUG>0
         if(retvals){
            retvals->methode="64";
            retvals->pz_methode=64;
         }
#endif
         pz = (kto[0]-'0') * 9
            + (kto[1]-'0') * 10
            + (kto[2]-'0') * 5
            + (kto[3]-'0') * 8
            + (kto[4]-'0') * 4
            + (kto[5]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ7;

/*  Berechnung nach der Methode 65 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 65                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2.                        #
 * # Die Kontonummer ist zehnstellig: G G G S S S S P K U               #
 * # G = Geschäftstellennummer                                          #
 * # S = Stammnummer                                                    #
 * # P = Prüfziffer                                                     #
 * # K = Kontenartziffer                                                #
 * # U = Unterkontonummer                                               #
 * # Die Berechnung erfolgt wie bei Verfahren 00 über Geschäfts-        #
 * # stellennummer und Stammnummer mit der Gewichtung 2, 1, 2,...       #
 * # Ausnahme: Ist die Kontenartziffer (neunte Stelle der Konto-        #
 * # nummer) eine 9, so werden die neunte und zehnte Stelle der         #
 * # Kontonummer in die Prüfziffernermittlung einbezogen. Die           #
 * # Berechnung erfolgt dann über die Geschäftsstellennummer,           #
 * # Stammnummer, Kontenartziffer und Unterkontonummer mit der          #
 * # Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2.                              #
 * ######################################################################
 */
      case 65:
#if DEBUG>0
         if(retvals){
            retvals->methode="65";
            retvals->pz_methode=65;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else

         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(kto[8]=='9'){
            p1=(kto[9]-'0')*2;
            if(p1>9)p1-=9;
            pz+=p1+9;
         }
         pz=pz%10;
         if(pz)pz=10-pz;
         CHECK_PZ8;

/*  Berechnung nach der Methode 66 +§§§4 */
/*
 * ######################################################################
 * #          Berechnung nach der Methode 66  (geändert zum 3.3.2014)   #
 * ######################################################################
 * # Aufbau der 9-stelligen Kontonummer (innerhalb des                  #
 * # zwischenbetrieblich 10-stelligen Feldes)                           #
 * # Stelle    1    = gehört nicht zur Kontonummer, muss                #
 * #                  daher 0 sein                                      #
 * #           2    = Stammnunmmer                                      #
 * #           3-4  = Unterkontonummer, wird bei der Prüfziffer-        #
 * #                  berechnung nicht berücksichtigt                   #
 * #           5-9  = Stammnummer                                       #
 * #           10   = Prüfziffer                                        #
 * # Der 9-stelligen Kontonummer wird für die Prüfzifferberechnung      #
 * # eine 0 vorangestellt. Die Prüfziffer steht in Stelle 10. Die für   #
 * # die Berechnung relevante 6-stellige Stammnummer (Kundenummer)      #
 * # befindet sich in den Stellen 2 und  5 bis 9. Die zweistellige      #
 * # Unterkontonummer (Stellen 3 und 4) wird nicht in das               #
 * # Prüfzifferberechnungsverfahren mit einbezogen und daher mit 0      #
 * # gewichtet. Die einzelnen Stellen der Stammnummer sind von rechts   #
 * # nach links mit den Ziffern 2, 3, 4, 5, 6, 0, 0, 7 zu               #
 * # multiplizieren. Die jeweiligen Produkte werden addiert. Die        #
 * # Summe ist durch 11 zu dividieren. Bei einem verbleibenden Rest     #
 * # von 0 ist die Prüfziffer 1. Bei einem Rest von 1 ist die           #
 * # Prüfziffer 0 Verbleibt ein Rest von 2 bis 10, so wird dieser vom   #
 * # Divison (11) subtrahiert. Die Differenz ist dann die Prüfziffer.   #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist die Stelle 2 der Kontonummer der Wert = 9, ist die Kontonummer #
 * # nicht prüfziffergesichert; es gilt die Methode 09 (keine           #
 * # Prüfzifferberechnung)                                              #
 * ######################################################################
 */
      case 66:
#if DEBUG>0
      case 2066:
         if(retvals){
            retvals->methode="66b";
            retvals->pz_methode=2066;
         }
#endif
         if(kto[1]=='9')return OK_NO_CHK;
#if DEBUG>0
      case 1066:
         if(retvals){
            retvals->methode="66a";
            retvals->pz_methode=1066;
         }
#endif
         if(*kto!='0')return INVALID_KTO;
         pz = (kto[1]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<2)
            pz=1-pz;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 67 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 67                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2.                        #
 * # Die Kontonummer ist zehnstellig. Die Berechnung erfolgt wie bei    #
 * # Verfahren 00. Es ist jedoch zu beachten, daß die zweistellige      #
 * # Unterkontonummer (Stellen 9 und 10) nicht in das Prüfziffern-      #
 * # verfahren mit einbezogen werden darf. Die für die Berechnung       #
 * # relevante siebenstellige Stammnummer befindet sich in den          #
 * # Stellen 1 bis 7, die Prüfziffer in der Stelle 8.                   #
 * ######################################################################
 */
      case 67:
#if DEBUG>0
         if(retvals){
            retvals->methode="67";
            retvals->pz_methode=67;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else

         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ8;

/*  Berechnung nach der Methode 68 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 68                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2.                  #
 * # Die Kontonummern sind 6 bis 10stellig und enthalten keine          #
 * # führenden Nullen. Die erste Stelle von rechts ist die              #
 * # Prüfziffer. Die Berechnung erfolgt wie bei Verfahren 00,           #
 * # hierbei sind jedoch folgende Besonderheiten zu beachten:           #
 * # Bei 10stelligen Kontonummern erfolgt die Berechnung für die        #
 * # 2. bis 7. Stelle (von rechts!). Stelle 7 muß eine 9 sein.          #
 * # 6 bis 9stellige Kontonummern sind in zwei Varianten prüfbar.       #
 * # Variante 1: voll prüfbar.                                          #
 * # Ergibt die Berechnung nach Variante 1 einen Prüfziffernfehler,     #
 * # muß Variante 2 zu einer korrekten Prüfziffer führen.               #
 * # Variante 2: Stellen 7 und 8 werden nicht geprüft.                  #
 * # 9stellige Kontonummern im Nummerenbereich 400000000 bis            #
 * # 4999999999 sind nicht prüfbar, da diese Nummern keine              #
 * # Prüfziffer enthalten.                                              #
 * ######################################################################
 */
      case 68:
#if DEBUG>0
         if(retvals){
            retvals->methode="68";
            retvals->pz_methode=68;
         }
#endif
            /* die Kontonummer muß mindestens 6-stellig sein (ohne führende Nullen) */
         if(kto[0]=='0' && kto[1]=='0' && kto[2]=='0' && kto[3]=='0' && kto[4]=='0')
            return INVALID_KTO;

            /* Sonderfall: keine Prüfziffer */
         if(*kto=='0' && *(kto+1)=='4'){
#if DEBUG>0
            pz= *(kto+9)-'0';
#endif
            return OK_NO_CHK;
         }

            /* 10stellige Kontonummern */
#if DEBUG>0
      case 1068:
         if(retvals){
            retvals->methode="68a";
            retvals->pz_methode=1068;
         }
#endif
         if(*kto!='0'){
            if(*(kto+3)!='9')return INVALID_KTO;
#ifdef __ALPHA
         pz = 9           /* 7. Stelle von rechts */
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=9+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_40;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }

            /* 6 bis 9stellige Kontonummern: Variante 1 */
#if DEBUG>0
      case 2068:
         if(retvals){
            retvals->methode="68b";
            retvals->pz_methode=2068;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* 6 bis 9stellige Kontonummern: Variante 2 */
#if DEBUG>0
      case 3068:
         if(retvals){
            retvals->methode="68c";
            retvals->pz_methode=3068;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[1]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

         pz=(kto[1]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_40;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 69 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 69                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8.                        #
 * # Die Berechnung erfolgt wie bei Verfahren 28. Ergibt die            #
 * # Berechnung einen Prüfziffernfehler, so ist die Prüfziffer          #
 * # nach Variante II zu ermitteln (s.u.).                              #
 * # Ausnahmen:                                                         #
 * # Für den Kontonummernkreis 9300000000 - 9399999999 ist keine        #
 * # Prüfziffernberechnung möglich = Kennziffer 09.                     #
 * # Für den Kontonummernkreis 9700000000 - 9799999999 ist die          #
 * # Prüfziffernberechnung wie folgt vorzunehmen (Variante II):         #
 * # Die Position der einzelnen Ziffern von rechts nach links           #
 * # innerhalb der Kontonummer gibt die Zeile 1 bis 4 der Trans-        #
 * # formationstabelle an. Aus ihr sind die Übersetzungswerte zu        #
 * # summieren. Die Einerstelle wird von 10 subtrahiert und stellt      #
 * # die Prüfziffer dar.                                                #
 * # Transformationstabelle:                                            #
 * # Ziffer    : 0123456789                                             #
 * # Zeile 1   : 0159374826                                             #
 * # Zeile 2   : 0176983254                                             #
 * # Zeile 3   : 0184629573                                             #
 * # Zeile 4   : 0123456789                                             #
 * ######################################################################
 */
      case 69:
#if DEBUG>0
         if(retvals){
            retvals->methode="69";
            retvals->pz_methode=69;
         }
#endif
            /* Sonderfall 93xxxxxxxx: Keine Prüfziffer */
         if(*kto=='9' && *(kto+1)=='3')return OK_NO_CHK;

            /* Variante 1 */
#if DEBUG>0
      case 1069:
         if(retvals){
            retvals->methode="69a";
            retvals->pz_methode=1069;
         }
#endif
            /* Sonderfall 97xxxxxxxx nur über Variante 2 */
         if(*kto!='9' || *(kto+1)!='7'){
            pz = (kto[0]-'0') * 8
               + (kto[1]-'0') * 7
               + (kto[2]-'0') * 6
               + (kto[3]-'0') * 5
               + (kto[4]-'0') * 4
               + (kto[5]-'0') * 3
               + (kto[6]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX8;
         }

            /* Variante 2 */
#if DEBUG>0
      case 2069:
         if(retvals){
            retvals->methode="69b";
            retvals->pz_methode=2069;
         }
#endif
         pz = m10h_digits[0][(unsigned int)(kto[0]-'0')]
            + m10h_digits[3][(unsigned int)(kto[1]-'0')]
            + m10h_digits[2][(unsigned int)(kto[2]-'0')]
            + m10h_digits[1][(unsigned int)(kto[3]-'0')]
            + m10h_digits[0][(unsigned int)(kto[4]-'0')]
            + m10h_digits[3][(unsigned int)(kto[5]-'0')]
            + m10h_digits[2][(unsigned int)(kto[6]-'0')]
            + m10h_digits[1][(unsigned int)(kto[7]-'0')]
            + m10h_digits[0][(unsigned int)(kto[8]-'0')];
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnungsmethoden 70 bis 79 +§§§3
   Berechnung nach der Methode 70 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 70                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7.                           #
 * # Die Kontonummer ist zehnstellig. Die einzelnen Stellen der         #
 * # Kontonummer sind von rechts nach links mit den Ziffern             #
 * # 2,3,4,5,6,7,2,3,4 zu multiplizieren. Die Berechnung erfolgt wie    #
 * # bei Verfahren 06.                                                  #
 * # Ausnahme: Ist die 4. Stelle der Kontonummer = 5 oder die 4. -      #
 * # 5. Stelle der Kontonummer = 69, so werden die Stellen 1 - 3        #
 * # nicht in die Prüfziffernermittlung einbezogen.                     #
 * ######################################################################
 */
      case 70:
#if DEBUG>0
         if(retvals){
            retvals->methode="70";
            retvals->pz_methode=70;
         }
#endif
         if(*(kto+3)=='5'){
            pz = 5 * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;
            MOD_11_176;   /* pz%=11 */
         }
         else if(*(kto+3)=='6' && *(kto+4)=='9'){
            pz = 6 * 7
               + 9 * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;
            MOD_11_176;   /* pz%=11 */
         }
         else{
            pz = (kto[0]-'0') * 4
               + (kto[1]-'0') * 3
               + (kto[2]-'0') * 2
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;
            MOD_11_176;   /* pz%=11 */
         }
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 71 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 71                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 6, 5, 4, 3, 2, 1.                           #
 * # Die Kontonummer ist immer 10-stellig. Die Stellen 2 bis 7          #
 * # sind von links nach rechts mit den Ziffern 6, 5, 4, 3, 2, 1 zu     #
 * # multiplizieren. Die Ergebnisse sind dann ohne Quersummenbildung    #
 * # zu addieren. Die Summe ist durch 11 zu dividieren.                 #
 * # Der verbleibende Rest wird vom Divisor (11) subtrahiert.           #
 * # Das Ergebnis ist die Prüfziffer.                                   #
 * # Ausnahmen: Verbleibt nach der Division durch 11 kein Rest, ist     #
 * # die Prüfziffer 0. Ergibt sich als Rest 1, entsteht bei der         #
 * # Subtraktion 11 ./. 1 = 10; die Zehnerstelle (1) ist dann           #
 * # die Prüfziffer.                                                    #
 * ######################################################################
 */
      case 71:
#if DEBUG>0
         if(retvals){
            retvals->methode="71";
            retvals->pz_methode=71;
         }
#endif
         pz = (kto[1]-'0') * 6
            + (kto[2]-'0') * 5
            + (kto[3]-'0') * 4
            + (kto[4]-'0') * 3
            + (kto[5]-'0') * 2
            + (kto[6]-'0');

         MOD_11_176;   /* pz%=11 */
         if(pz>1)pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 72 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 72                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1.                           #
 * # Die Kontonummer ist zehnstellig. Die Berechnung erfolgt wie bei    #
 * # Verfahren 00. Es ist jedoch zu beachten, daß die zweistellige      #
 * # Unterkontonummer (Stellen 1 und 2) und die Artziffer (Stelle 3)    #
 * # nicht in das Prüfziffernverfahren mit einbezogen werden.           #
 * # Die für die Berechnung relevante sechsstellige Kundennummer        #
 * # befindet sich in den Stellen 4 bis 9, die Prüfziffer in der        #
 * # Stelle 10.                                                         #
 * ######################################################################
 */
      case 72:
#if DEBUG>0
         if(retvals){
            retvals->methode="72";
            retvals->pz_methode=72;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 73 +§§§4 */
/*
 * ######################################################################
 * #    Berechnung nach der Methode 73  (geändert zum 6.12.2004)        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummer ist durch linksbündiges Auffüllen mit Nullen       #
 * # 10-stellig darzustellen. Die 10. Stelle der Kontonummer ist die    #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1                            #
 * # Die Stellen 4 bis 9 der Kontonummer werden von rechts nach links   #
 * # mit den Ziffern 2, 1, 2, 1, 2, 1 multipliziert. Die Berechnung und #
 * # Ergebnisse entsprechen dem Verfahren 00.                           #
 * #                                                                    #
 * # Führt die Berechnung nach Variante 1 zu einem Prüfzifferfehler,    #
 * # ist eine weitere Berechnung nach Variante 2 vorzunehmen.           #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2                               #
 * # Das Berechnungsverfahren entspricht Variante 1, es ist jedoch zu   #
 * # beachten, dass nur die Stellen 5 bis 9 in das Prüfziffern-         #
 * # berechnungsverfahren einbezogen werden.                            #
 * #                                                                    #
 * # Führt die Berechnung auch nach Variante 2 zu einem Prüfziffer-     #
 * # fehler, ist die Berechnung nach Variante 3 vorzunehmen:            #
 * #                                                                    #
 * # Variante 3                                                         #
 * # Modulus 7, Gewichtung 2, 1, 2, 1, 2 Das Berechnungsverfahren       #
 * # entspricht Variante 2. Die Summe der Produkt-Quersummen ist jedoch #
 * # durch 7 zu dividieren. Der verbleibende Rest wird vom Divisor (7)  #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt nach der   #
 * # Division kein Rest, ist die Prüfziffer = 0                         #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist nach linksbündiger Auffüllung mit Nullen auf 10 Stellen die 3. #
 * # Stelle der Kontonummer = 9 (Sachkonten), so erfolgt die Berechnung #
 * # gemäß der Ausnahme in Methode 51 mit den gleichen Ergebnissen und  #
 * # Testkontonummern.                                                  #
 * ######################################################################
 */

      case 73:
                /* Ausnahme, Variante 1 */
         if(*(kto+2)=='9'){   /* Berechnung wie in Verfahren 51 */
#if DEBUG>0
      case 4073:
         if(retvals){
            retvals->methode="73d";
            retvals->pz_methode=4073;
         }
#endif
            pz =         9 * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

            /* Ausnahme, Variante 2 */
#if DEBUG>0
      case 5073:
         if(retvals){
            retvals->methode="73e";
            retvals->pz_methode=5073;
         }
#endif
               pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               +            9 * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

               MOD_11_352;   /* pz%=11 */
               if(pz<=1)
                  pz=0;
               else
                  pz=11-pz;
               CHECK_PZ10;
            }

#if DEBUG>0
      case 1073:
         if(retvals){
            retvals->methode="73a";
            retvals->pz_methode=1073;
         }
#endif
#ifdef __ALPHA
         pz1= ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

         pz1=(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz1+=(kto[4]-'0')*2; else pz1+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz1+=(kto[6]-'0')*2; else pz1+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz1+=(kto[8]-'0')*2; else pz1+=(kto[8]-'0')*2-9;
#endif
         pz=pz1+(kto[3]-'0');
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

#if DEBUG>0
      case 2073:
         if(retvals){
            retvals->methode="73b";
            retvals->pz_methode=2073;
         }
#endif
#if DEBUG>0
#ifdef __ALPHA
         pz = ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

         pz=(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
#else
         pz=pz1;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

#if DEBUG>0
      case 3073:
         if(retvals){
            retvals->methode="73c";
            retvals->pz_methode=3073;
         }
#endif
#if DEBUG
#ifdef __ALPHA
         pz = ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

         pz=(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
#else
         pz=pz1;
#endif
         MOD_7_56;   /* pz%=7 */
         if(pz)pz=7-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 74 +§§§4 */
/*
 * ######################################################################
 * #    Berechnung nach der Methode 74 (geändert zum 4.6.2007)          #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2 ff.                           #
 * # Die Kontonummer (2- bis 10-stellig) ist durch linksbündige         #
 * # Nullenauffüllung 10-stellig darzustellen. Die 10. Stelle ist       #
 * # per Definition die Prüfziffer. Die für die Berechnung              #
 * # relevanten Stellen werden von rechts nach links mit den Ziffern    #
 * # 2, 1, 2, 1, 2 ff. multipliziert. Die weitere Berechnung und die    #
 * # Ergebnisse entsprechen dem Verfahren 00.                           #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Bei 6-stelligen Kontonummern ist folgende Besonderheit zu          #
 * # beachten.                                                          #
 * # Ergibt die erste Berechnung der Prüfziffer nach dem Verfahren 00   #
 * # einen Prüfziffernfehler, so ist eine weitere Berechnung            #
 * # vorzunehmen. Hierbei ist die Summe der Produkte auf die nächste    #
 * # Halbdekade hochzurechnen. Die Differenz ist die Prüfziffer.        #
 * ######################################################################
 */
      case 74:
         if(kto[0]=='0' && kto[1]=='0' && kto[2]=='0' && kto[3]=='0' && kto[4]=='0'
               && kto[5]=='0' && kto[6]=='0' && kto[7]=='0' && kto[8]=='0')return INVALID_KTO;
#if DEBUG>0
      case 1074:
         if(retvals){
            retvals->methode="74a";
            retvals->pz_methode=1074;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=pz1=(kto[0]-'0')*2; else pz+=pz1=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=pz1=(kto[2]-'0')*2; else pz+=pz1=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=pz1=(kto[4]-'0')*2; else pz+=pz1=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=pz1=(kto[6]-'0')*2; else pz+=pz1=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=pz1=(kto[8]-'0')*2; else pz+=pz1=(kto[8]-'0')*2-9;
#endif
         pz1=pz;  /* Summe merken für Fall b */
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

         if(*kto=='0' && *(kto+1)=='0' && *(kto+2)=='0' && *(kto+3)=='0' && *(kto+4)!='0'){

#if DEBUG>0
      case 2074:
         if(retvals){
            retvals->methode="74b";
            retvals->pz_methode=2074;
         }
#endif
#if DEBUG>0
            if(untermethode){

                  /* pz wurde noch nicht berechnet; jetzt erledigen.
                   * Da dieser Code nur im DEBUG-Fall auftritt, wurde er
                   * für VMS nicht optimiert.
                   */
               pz1=(kto[5]-'0')+(kto[7]-'0');
               if(kto[4]<'5')pz1+=(kto[4]-'0')*2; else pz1+=(kto[4]-'0')*2-9;
               if(kto[6]<'5')pz1+=(kto[6]-'0')*2; else pz1+=(kto[6]-'0')*2-9;
               if(kto[8]<'5')pz1+=(kto[8]-'0')*2; else pz1+=(kto[8]-'0')*2-9;
            }
#endif
               /* für 6-stellige Kontonummern hochrechnen auf die nächste
                * Halbdekade. Diese Version benutzt nur noch "echte"
                * Halbdekaden (5,15,25...); die "unechten" Halbdekaden 10,20,30
                * wurden schon beim ersten Test in Methode 74a getestet. Für
                * den Test reicht es, zu der alten Zwischensumme (die bereits
                * zur unechten Halbdekade getestet wurde) 5 zu addieren (bei
                * einer Zwischensumme<5) bzw. zu subtrahieren (bei einer
                * Zwischensumme>=5) und den Wert mit der Soll-Prüfziffer zu
                * vergleichen. Mit dieser Methode kommt man jeweils zur
                * "nächsten" Halbdekade.
                *
                * Es bleibt allerdings noch die Frage, ob es für die Methode
                * 74b auch Prüfziffern <5 gibt; mit der angegebenen
                * Berechnungsmethode werden diese als falsch zurückgewiesen,
                * was allerdings auch mit dem Verhalten von anderen Programmen
                * übereinstimmt.
                */
            pz=pz1;
            if(pz<5)
               pz+=5;
            else
               pz-=5;
            MOD_10_80;
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }
         else
            return FALSE;

/*  Berechnung nach der Methode 75 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 75                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2.                              #
 * # Die Kontonummer (6-, 7- oder 9-stellig) ist durch linksbündige     #
 * # Nullenauffüllung 10-stellig darzustellen. Die für die Berech-      #
 * # nung relevante 5-stellige Stammnummer wird von links nach          #
 * # rechts mit den Ziffern 2, 1, 2, 1, 2 multipliziert. Die weitere    #
 * # Berechnung und die Ergebnisse entsprechen dem Verfahren 00.        #
 * # Bei 6- und 7-stelligen Kontonummern befindet sich die für die      #
 * # Berechnung relevante Stammnummer in den Stellen 5 bis 9, die       #
 * # Prüfziffer in Stelle 10 der Kontonummer.                           #
 * # Bei 9-stelligen Kontonummern befindet sich die für die Berech-     #
 * # nung relevante Stammnummer in den Stellen 2 bis 6, die Prüf-       #
 * # ziffer in der 7. Stelle der Kontonummer. Ist die erste Stelle      #
 * # der 9-stelligen Kontonummer = 9 (2. Stelle der "gedachten"         #
 * # Kontonummer), so befindet sich die für die Berechnung relevante    #
 * # Stammnummer in den Stellen 3 bis 7, die Prüfziffer in der 8.       #
 * # Stelle der Kontonummer.                                            #
 * ######################################################################
 */
      case 75:
#if DEBUG>0
         if(retvals){
            retvals->methode="75";
            retvals->pz_methode=75;
         }
#endif
         if(*kto!='0')return INVALID_KTO;   /* 10-stellige Kontonummer */
         if(*kto=='0' && *(kto+1)=='0'){   /* 6/7-stellige Kontonummer */
#if DEBUG>0
      case 1075:
         if(retvals){
            retvals->methode="75a";
            retvals->pz_methode=1075;
         }
#endif
            if(*(kto+2)!='0' || (*(kto+2)=='0' && *(kto+3)=='0' && *(kto+4)=='0'))
               return INVALID_KTO;   /* 8- oder <6-stellige Kontonummer */
#ifdef __ALPHA
            pz = ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz=(kto[5]-'0')+(kto[7]-'0');
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }
         else if(*(kto+1)=='9'){   /* 9-stellige Kontonummer, Variante 2 */
#if DEBUG>0
      case 2075:
         if(retvals){
            retvals->methode="75b";
            retvals->pz_methode=2075;
         }
#endif
#ifdef __ALPHA
            pz = ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else
            pz=(kto[3]-'0')+(kto[5]-'0');
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif
         MOD_10_40;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ8;
         }
         else{   /* 9-stellige Kontonummer, Variante 1 */
#if DEBUG>0
      case 3075:
         if(retvals){
            retvals->methode="75c";
            retvals->pz_methode=3075;
         }
#endif
#ifdef __ALPHA
            pz = ((kto[1]<'5') ? (kto[1]-'0')*2 : (kto[1]-'0')*2-9)
               +  (kto[2]-'0')
               + ((kto[3]<'5') ? (kto[3]-'0')*2 : (kto[3]-'0')*2-9)
               +  (kto[4]-'0')
               + ((kto[5]<'5') ? (kto[5]-'0')*2 : (kto[5]-'0')*2-9);
#else
            pz=(kto[2]-'0')+(kto[4]-'0');
            if(kto[1]<'5')pz+=(kto[1]-'0')*2; else pz+=(kto[1]-'0')*2-9;
            if(kto[3]<'5')pz+=(kto[3]-'0')*2; else pz+=(kto[3]-'0')*2-9;
            if(kto[5]<'5')pz+=(kto[5]-'0')*2; else pz+=(kto[5]-'0')*2-9;
#endif
         MOD_10_40;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ7;
         }

/*  Berechnung nach der Methode 76 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 76                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5 ff.                              #
 * # Die einzelnen Stellen der für die Berechnung der Prüfziffer        #
 * # relevanten 5-, 6- oder 7-stelligen Stammnummer sind von rechts     #
 * # nach links mit den Ziffern 2, 3, 4, 5 ff. zu multiplizieren.       #
 * # Die jeweiligen Produkte werden addiert. Die Summe ist durch 11     #
 * # zu dividieren. Der verbleibende Rest ist die Prüfziffer. Ist       #
 * # der Rest 10, kann die Kontonummer nicht verwendet werden.          #
 * # Darstellung der Kontonummer: ASSSSSSPUU.                           #
 * # Ist die Unterkontonummer "00", kann es vorkommen, daß sie auf      #
 * # Zahlungsbelegen nicht angegeben ist. Die Prüfziffer ist dann       #
 * # an die 10. Stelle gerückt.                                         #
 * # Die Kontoart (1. Stelle) kann den Wert 0, 4, 6, 7, 8 oder 9 haben. #
 * ######################################################################
 */
      case 76:
#if DEBUG>0
      case 1076:
         if(retvals){
            retvals->methode="76a";
            retvals->pz_methode=1076;
         }
#endif
         if((p1= *kto)=='1' || p1=='2' || p1=='3' || p1=='5'){
            pz= -3;
            return INVALID_KTO;
         }
         pz = (kto[1]-'0') * 7
            + (kto[2]-'0') * 6
            + (kto[3]-'0') * 5
            + (kto[4]-'0') * 4
            + (kto[5]-'0') * 3
            + (kto[6]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         CHECK_PZX8;

         if(kto[0]!='0' || kto[1]!='0'){
#if DEBUG>0
            pz= -1;
#endif
            return FALSE;
         }

#if DEBUG>0
      case 2076:
         if(retvals){
            retvals->methode="76b";
            retvals->pz_methode=2076;
         }
#endif
         if((p1=kto[2])=='1' || p1=='2' || p1=='3' || p1=='5'){
#if DEBUG>0
            pz= -3;
#endif
            return INVALID_KTO;
         }
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz==10){
            pz= -2;
            return INVALID_KTO;
         }
         CHECK_PZ10;

/*  Berechnung nach der Methode 77 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 77                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 1, 2, 3, 4, 5.                              #
 * # Die Kontonummer ist 10-stellig. Die für die Berechnung             #
 * # relevanten Stellen 6 bis 10 werden von rechts nach links mit       #
 * # den Ziffern 1, 2, 3, 4, 5 multipliziert. Die Produkte werden       #
 * # addiert. Die Summe ist durch 11 zu dividieren. Verbleibt nach      #
 * # der Division der Summe durch 11 ein Rest, ist folgende neue        #
 * # Berechnung durchzuführen:                                          #
 * # Modulus 11, Gewichtung 5, 4, 3, 4, 5.                              #
 * # Ergibt sich bei der erneuten Berechnung wiederum ein Rest,         #
 * # dann ist die Kontonummer falsch.                                   #
 * ######################################################################
 */
      case 77:
#if DEBUG>0
      case 1077:
         if(retvals){
            retvals->methode="77a";
            retvals->pz_methode=1077;
         }
#endif
         pz = (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2
            + (kto[9]-'0');

         MOD_11_88;   /* pz%=11 */
         if(pz==0)return OK;
#if DEBUG>0
         if(untermethode)return INVALID_KTO;
#endif
#if DEBUG>0
      case 2077:
         if(retvals){
            retvals->methode="77b";
            retvals->pz_methode=2077;
         }
#endif
         pz = (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 4
            + (kto[9]-'0') * 5;

         MOD_11_176;   /* pz%=11 */
         if(pz==0)
            return OK;
         else
#if DEBUG>0
         if(untermethode)
            return INVALID_KTO;
         else
#endif
            return FALSE;

/*  Berechnung nach der Methode 78 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 78                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2.                  #
 * # Die Berechnung erfolgt wie bei Verfahren 00. Ausnahme:             #
 * # 8-stellige Kontonummern sind nicht prüfbar, da diese Nummern       #
 * # keine Prüfziffer enthalten.                                        #
 * ######################################################################
 */
      case 78:
#if DEBUG>0
         if(retvals){
            retvals->methode="78";
            retvals->pz_methode=78;
         }
#endif
         if(*kto=='0' && *(kto+1)=='0' && *(kto+2)!='0')
#if BAV_KOMPATIBEL
            return BAV_FALSE;
#else
            return OK_NO_CHK;
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 79 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 79                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2 ff.                     #
 * # Die Kontonummer ist 10-stellig. Die Berechnung und Ergebnisse      #
 * # entsprechen dem Verfahren 00. Es ist jedoch zu beachten, dass      #
 * # die Berechnung vom Wert der 1. Stelle der Kontonummer abhängig     #
 * # ist.                                                               #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Die 1. Stelle der Kontonummer hat die Ziffer 3, 4, 5, 6, 7         #
 * # oder 8                                                             #
 * # Die für die Berechnung relevanten Stellen der Kontonummer          #
 * # befinden sich in den Stellen 1 bis 9. Die 10. Stelle ist per       #
 * # Definition die Prüfziffer.                                         #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Die 1. Stelle der Kontonummer hat die Ziffer 1, 2 oder 9           #
 * # Die für die Berechnung relevanten Stellen der Kontonummer          #
 * # befinden sich in den Stellen 1 bis 8. Die 9. Stelle ist die        #
 * # Prüfziffer der 10-stelligen Kontonummer.                           #
 * #                                                                    #
 * # Kontonummern, die in der 1. Stelle eine 0 haben,                   #
 * # wurden nicht vergeben und gelten deshalb als falsch.               #
 * ######################################################################
 */
      case 79:
#if DEBUG>0
         if(retvals){
            retvals->methode="79";
            retvals->pz_methode=79;
         }
#endif
         if(*kto=='0')return INVALID_KTO;
         if(*kto=='1' || *kto=='2' || *kto=='9'){
#ifdef __ALPHA
         pz =  (kto[0]-'0')
            + ((kto[1]<'5') ? (kto[1]-'0')*2 : (kto[1]-'0')*2-9)
            +  (kto[2]-'0')
            + ((kto[3]<'5') ? (kto[3]-'0')*2 : (kto[3]-'0')*2-9)
            +  (kto[4]-'0')
            + ((kto[5]<'5') ? (kto[5]-'0')*2 : (kto[5]-'0')*2-9)
            +  (kto[6]-'0')
            + ((kto[7]<'5') ? (kto[7]-'0')*2 : (kto[7]-'0')*2-9);
#else
         pz =(kto[0]-'0')+(kto[2]-'0')+(kto[4]-'0')+(kto[6]-'0');
         if(kto[1]<'5')pz+=(kto[1]-'0')*2; else pz+=(kto[1]-'0')*2-9;
         if(kto[3]<'5')pz+=(kto[3]-'0')*2; else pz+=(kto[3]-'0')*2-9;
         if(kto[5]<'5')pz+=(kto[5]-'0')*2; else pz+=(kto[5]-'0')*2-9;
         if(kto[7]<'5')pz+=(kto[7]-'0')*2; else pz+=(kto[7]-'0')*2-9;
#endif

            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ9;
         }
         else{
#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }

/* Berechnungsmethoden 80 bis 89 +§§§3
   Berechnung nach der Methode 80 +§§§4 */
/*
 * ######################################################################
 * #    Berechnung nach der Methode 80 (geändert zum 8.6.2004)          #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2.                              #
 * # Die Berechnung und die möglichen Ergebnisse entsprechen dem        #
 * # Verfahren 00; es ist jedoch  zu beachten, daß nur die Stellen      #
 * # 5 bis 9 in das Prüfziffernberechnungsverfahren einbezogen          #
 * # werden.                                                            #
 * # Führt die Berechnung zu einem Prüfziffernfehler, so ist die        #
 * # Berechnung nach Variante 2 vorzunehmen. Das Berechnungsverfahren   #
 * # entspricht Variante 1. Die Summe der Produkte ist jedoch durch     #
 * # 7 zu dividieren. Der verbleibende Rest wird vom Divisor (7)        #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt nach       #
 * # der Division kein Rest, ist die Prüfziffer 0.                      #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist nach linksbündiger Auffüllung mit Nullen auf 10 Stellen die    #
 * # 3. Stelle der Kontonummer = 9 (Sachkonten), so erfolgt die         #
 * # Berechnung gemäß der Ausnahme in Methode 51 mit den gleichen       #
 * # Ergebnissen und Testkontonummern.                                  #
 * ######################################################################
 */

      case 80:

                /* Ausnahme, Variante 1 */
         if(*(kto+2)=='9'){   /* Berechnung wie in Verfahren 51 */
#if DEBUG>0
      case 3080:
         if(retvals){
            retvals->methode="80c";
            retvals->pz_methode=3080;
         }
#endif
            pz =         9 * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

            /* Ausnahme, Variante 2 */
#if DEBUG>0
      case 4080:
         if(retvals){
            retvals->methode="80d";
            retvals->pz_methode=4080;
         }
#endif
               pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               +            9 * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

               MOD_11_352;   /* pz%=11 */
               if(pz<=1)
                  pz=0;
               else
                  pz=11-pz;
               CHECK_PZ10;
            }

            /* Variante 1 */
#if DEBUG>0
      case 1080:
         if(retvals){
            retvals->methode="80a";
            retvals->pz_methode=1080;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_10_40;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Variante 2 */
#if DEBUG>0
      case 2080:
         if(retvals){
            retvals->methode="80b";
            retvals->pz_methode=2080;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_7_56;   /* pz%=10 */
         if(pz)pz=7-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 81 +§§§4 */
/*
 * ######################################################################
 * #    Berechnung nach der Methode 81  (geändert zum 6.9.2004)         #
 * ######################################################################
 * #                                                                    #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * # Die Kontonummer ist durch linksbündige Nullenauffüllung stellig    #
 * # darzustellen. Die 10. Stelle ist per Definition Prüfziffer. Die    #
 * # für die Berechnung relevanten Stellen werden von rechts nach       #
 * # links mit den Ziffern 2, 3, 4, 5, 6, multipliziert. Die weitere    #
 * # Berechnung und die möglichen Ergebnisse entsprechen dem Verfahren  #
 * # 32.                                                                #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist nach linksbündiger Auffüllung mit Nullen auf 10 Stellen 3.     #
 * # Stelle der Kontonummer = 9 (Sachkonten), so erfolgt Berechnung     #
 * # gemäß der Ausnahme in Methode 51 mit gleichen Ergebnissen und      #
 * # Testkontonummern.                                                  #
 * ######################################################################
 */

      case 81:
                /* Ausnahme, Variante 1 */
         if(*(kto+2)=='9'){   /* Berechnung wie in Verfahren 51 */
#if DEBUG>0
      case 2081:
         if(retvals){
            retvals->methode="81b";
            retvals->pz_methode=2081;
         }
#endif
            pz =         9 * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

            /* Ausnahme, Variante 2 */
#if DEBUG>0
      case 3081:
         if(retvals){
            retvals->methode="81c";
            retvals->pz_methode=3081;
         }
#endif
               pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               +            9 * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

               MOD_11_352;   /* pz%=11 */
               if(pz<=1)
                  pz=0;
               else
                  pz=11-pz;
               CHECK_PZ10;
            }

#if DEBUG>0
      case 1081:
         if(retvals){
            retvals->methode="81a";
            retvals->pz_methode=1081;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 82 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 82                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7.                           #
 * # Sind die 3. und 4. Stelle der Kontonummer = 99, so erfolgt die     #
 * # Berechnung nach Verfahren 10, sonst nach Verfahren 33.             #
 * ######################################################################
 */
      case 82:
#if DEBUG>0
      case 1082:
         if(retvals){
            retvals->methode="82a";
            retvals->pz_methode=1082;
         }
#endif
            /* Verfahren 10 */
         if(*(kto+2)=='9' && *(kto+3)=='9'){
            pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               + (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_352;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

            /* Verfahren 33 */
#if DEBUG>0
      case 2082:
         if(retvals){
            retvals->methode="82b";
            retvals->pz_methode=2082;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 83 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 83                        #
 * ######################################################################
 * # 1. Kundenkonten                                                    #
 * # A. Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                         #
 * # B. Modulus 11, Gewichtung 2, 3, 4, 5, 6                            #
 * # C. Modulus  7, Gewichtung 2, 3, 4, 5, 6                            #
 * # Gemeinsame Anmerkungen für die Berechnungsverfahren:               #
 * # Die Kontonummer ist immer 10-stellig. Die für die Berechnung       #
 * # relevante Kundennummer (K) befindet sich bei der Methode A in      #
 * # den Stellen 4 bis 9 der Kontonummer und bei den Methoden B + C     #
 * # in den Stellen 5 - 9, die Prüfziffer in Stelle 10 der              #
 * # Kontonummer.                                                       #
 * #                                                                    #
 * # Ergibt die erste Berechnung der Prüfziffer nach dem Verfahren A    #
 * # einen Prüfzifferfehler, so sind weitere Berechnungen mit den       #
 * # anderen Methoden vorzunehmen. Kontonummern, die nach               #
 * # Durchführung aller 3 Berechnungsmethoden nicht zu einem            #
 * # richtigen Ergebnis führen, sind nicht prüfbar.                     #
 * #                                                                    #
 * # Methode A:                                                         #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * # Die Berechnung und möglichen Ergebnisse entsprechen                #
 * # dem Verfahren 32.                                                  #
 * #                                                                    #
 * # Methode B:                                                         #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6                               #
 * # Die Berechnung und möglichen Ergebnisse entsprechen                #
 * # dem Verfahren 33.                                                  #
 * #                                                                    #
 * # Methode C:                                                         #
 * # Kontonummern, die bis zur Methode C gelangen und in der 10.        #
 * # Stelle eine 7, 8 oder 9 haben, sind ungültig. Modulus 7,           #
 * # Gewichtung 2, 3, 4, 5, 6 Das Berechnungsverfahren entspricht       #
 * # Methode B. Die Summe der Produkte ist jedoch durch 7 zu            #
 * # dividieren. Der verbleibende Rest wird vom Divisor (7)             #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt kein       #
 * # Rest, ist die Prüfziffer 0.                                        #
 * #                                                                    #
 * # 2. Sachkonten                                                      #
 * # Berechnungsmethode:                                                #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8                         #
 * # Die Sachkontonummer ist immer 10-stellig. Die für die Berechnung   #
 * # relevante  Sachkontontenstammnummer (S) befindet sich in den       #
 * # Stellen 3 bis 9 der Kontonummer, wobei die 3. und 4. Stelle        #
 * # immer jeweils 9 sein müssen; die Prüfziffer ist in Stelle 10 der   #
 * # Sachkontonummer. Führt die Berechnung nicht zu einem richtigen     #
 * # Ergebnis, ist die Nummer nicht prüfbar.                            #
 * # Berechnung:                                                        #
 * # Die einzelnen Stellen der Sachkontonummern sind von rechts nach    #
 * # links mit den Ziffern 2, 3, 4, 5, 6, 7, 8 zu multiplizieren. Die   #
 * # jeweiligen Produkte werden addiert. Die Summe ist durch 11 zu      #
 * # dividieren. Der verbleibende Rest wird vom Divisor (11)            #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt nach der   #
 * # Division durch die 11 kein Rest, ist die Prüfziffer "0". Das       #
 * # Rechenergebnis "10" ist nicht verwendbar und muss auf eine         #
 * # Stelle reduziert werden. Die rechte Stelle Null findet als         #
 * # Prüfziffer Verwendung.                                             #
 * ######################################################################
 */
      case 83:
            /* Sachkonten */
#if DEBUG>0
      case 4083:
         if(retvals){
            retvals->methode="83d";
            retvals->pz_methode=4083;
         }
#endif
         if(*(kto+2)=='9' && *(kto+3)=='9'){
            pz =      9       * 8
               +      9       * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

            /* Methode A */
#if DEBUG>0
      case 1083:
         if(retvals){
            retvals->methode="83a";
            retvals->pz_methode=1083;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode B */
#if DEBUG>0
      case 2083:
         if(retvals){
            retvals->methode="83b";
            retvals->pz_methode=2083;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode C */
#if DEBUG>0
      case 3083:
         if(retvals){
            retvals->methode="83c";
            retvals->pz_methode=3083;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_7_112;   /* pz%=7 */
         if(pz)pz=7-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 84 +§§§4 */
/*
 * ######################################################################
 * #          Berechnung nach der Methode 84 (geändert zum 3.6.13)      #
 * ######################################################################
 * # Die Kontonummer ist durch linksbündige Nullenauffüllung            #
 * # 10-stellig darzustellen. Die 10. Stelle ist per Definition die     #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Es ist zu beachten, dass nur die Stellen 5 bis 9 in das            #
 * # Prüfzifferberechnungsverfahren einbezogen werden.                  #                                                                   #
 * #                                                                    #
 * # Methode A                                                          #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6                               #
 * # Die Berechnung und mögliche Ergebnisse entsprechen dem             #
 * # Verfahren 06.                                                      #
 * #                                                                    #
 * # Stelle-Nr.         1 2 3 4 5 6 7 8 9 10                            #
 * # Kontonummer        X X X X K K K K K  P                            #
 * # Gewichtung                 6 5 4 3 2                               #
 * #                                                                    #
 * # Führt die Berechnung nach Variante 1 zu einem Prüfziffer-          #
 * # fehler, ist die Berechnung nach Variante 2 vorzunehmen.            #
 * #                                                                    #
 * # Methode B                                                          #
 * # Modulus 7, Gewichtung 2, 3, 4, 5, 6                                #
 * # Die Berechnung und mögliche Ergebnisse entsprechen dem             #
 * # Verfahren 06. Dabei ist zu beachten, daß als Divisor 7 zu          #
 * # verwenden ist.                                                     #
 * #                                                                    #
 * # Stelle-Nr.         1 2 3 4 5 6 7 8 9 10                            #
 * # Kontonummer        X X X X K K K K K  P                            #
 * # Gewichtung                 6 5 4 3 2                               #
 * #                                                                    #
 * #                                                                    #
 * # Methode C                                                          #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2                               #
 * # Die Berechnung und mögliche Ergebnisse entsprechen dem             #
 * # Verfahren 06.                                                      #
 * #                                                                    #
 * # Stelle-Nr.         1 2 3 4 5 6 7 8 9 10                            #
 * # Kontonummer        X X X X K K K K K  P                            #
 * # Gewichtung                 2 1 2 1 2                               #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist nach linksbündiger Auffüllung mit Nullen auf 10 Stellen die    #
 * # 3. Stelle der Kontonummer = 9 (Sachkonten), so erfolgt die         #
 * # Berechnung gemäß der Ausnahme in Methode 51 mit den gleichen       #
 * # Ergebnissen und Testkontonummern.                                  #
 * ######################################################################
 */

      case 84:

                /* Ausnahme, Variante 1 */
         if(*(kto+2)=='9'){   /* Berechnung wie in Verfahren 51 */
#if DEBUG>0
      case 4084:
         if(retvals){
            retvals->methode="84d";
            retvals->pz_methode=4084;
         }
#endif
            pz =         9 * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

            /* Ausnahme, Variante 2 */
#if DEBUG>0
      case 5084:
         if(retvals){
            retvals->methode="84e";
            retvals->pz_methode=5084;
         }
#endif
               pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               +            9 * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

               MOD_11_352;   /* pz%=11 */
               if(pz<=1)
                  pz=0;
               else
                  pz=11-pz;
               CHECK_PZ10;
            }

            /* Methode A */
#if DEBUG>0
      case 1084:
         if(retvals){
            retvals->methode="84a";
            retvals->pz_methode=1084;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode B */
#if DEBUG>0
      case 2084:
         if(retvals){
            retvals->methode="84b";
            retvals->pz_methode=2084;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_7_112;   /* pz%=7 */
         if(pz)pz=7-pz;
         CHECK_PZX10;

            /* Methode C */
#if DEBUG>0
      case 3084:
         if(retvals){
            retvals->methode="84c";
            retvals->pz_methode=3084;
         }
#endif
         pz = (kto[4]-'0') * 2
            + (kto[5]-'0')
            + (kto[6]-'0') * 2
            + (kto[7]-'0')
            + (kto[8]-'0') * 2;

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 85 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 85                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6.                              #
 * # Wie Verfahren 83, jedoch folgende Ausnahme:                        #
 * # Sind die 3. und 4. Stelle der Kontonummer = 99, so ist folgende    #
 * # Prüfziffernberechnung maßgebend:                                   #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8.                        #
 * # Die für die Berechnung relevanten Stellen 3 bis 9 der Kontonr      #
 * # werden von rechts nach links mit den Ziffern 2, 3, 4, 5, 6, 7, 8   #
 * # multipliziert. Die weitere Berechnung und möglichen Ergebnisse     #
 * # entsprechen dem Verfahren 02.                                      #
 * ######################################################################
 */
      case 85:
#if DEBUG>0
      case 4085:
         if(retvals){
            retvals->methode="85d";
            retvals->pz_methode=4085;
         }
#endif
            /* Sachkonten */
         if(*(kto+2)=='9' && *(kto+3)=='9'){
            pz =      9       * 8
               +      9       * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz)pz=11-pz;
            INVALID_PZ10;
            CHECK_PZ10;
         }

            /* Methode A */
#if DEBUG>0
      case 1085:
         if(retvals){
            retvals->methode="85a";
            retvals->pz_methode=1085;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode B */
#if DEBUG>0
      case 2085:
         if(retvals){
            retvals->methode="85b";
            retvals->pz_methode=2085;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode C */
#if DEBUG>0
      case 3085:
         if(retvals){
            retvals->methode="85c";
            retvals->pz_methode=3085;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_7_112;   /* pz%=7 */
         if(pz)pz=7-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 86 +§§§4 */
/*
 * ######################################################################
 * #    Berechnung nach der Methode 86 (geändert zum 6.9.2004)          #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1                            #
 * #                                                                    #
 * # Methode A                                                          #
 * # Die Kontonummer ist durch linksbündige Nullenauffüllung 10-        #
 * # stellig darzustellen. Die Berechnung und die möglichen             #
 * # Ergebnisse entsprechen dem Verfahren 00; es ist jedoch zu          #
 * # beachten, dass nur die Stellen 4 bis 9 in das                      #
 * # Prüfzifferberechnungsverfahren einbezogen werden. Die Stelle       #
 * # 10 der Kontonummer ist die Prüfziffer.                             #
 * #                                                                    #
 * # Führt die Berechnung nach Methode A zu einem Prüfziffer-           #
 * # fehler, so ist die Berechnung nach Methode B vorzunehmen.          #
 * #                                                                    #
 * # Methode B                                                          #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * # Die Kontonummer ist durch linksbündige Nullenauffüllung 10-        #
 * # stellig darzustellen. Die Stellen 4 bis 9 der Kontonummer          #
 * # werden von rechts nach links mit den Ziffern 2, 3, 4, 5, 6, 7      #
 * # multipliziert. Die weitere Berechnung und die möglichen            #
 * # Ergebnisse entsprechen dem Verfahren 32. Die Stelle 10 ist die     #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist nach linksbündiger Auffüllung mit Nullen auf 10 Stellen        #
 * # die 3. Stelle der Kontonummer = 9 (Sachkonten), so erfolgt die     #
 * # Berechnung gemäß der Ausnahme in Methode 51 mit den gleichen       #
 * # Ergebnissen und Testkontonummern.                                  #
 * ######################################################################
 */

      case 86:

                /* Ausnahme, Variante 1 */
         if(*(kto+2)=='9'){   /* Berechnung wie in Verfahren 51 */
#if DEBUG>0
      case 3086:
         if(retvals){
            retvals->methode="86c";
            retvals->pz_methode=3086;
         }
#endif
            pz =         9 * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

            /* Ausnahme, Variante 2 */
#if DEBUG>0
      case 4086:
         if(retvals){
            retvals->methode="86d";
            retvals->pz_methode=4086;
         }
#endif
               pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               +            9 * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

               MOD_11_352;   /* pz%=11 */
               if(pz<=1)
                  pz=0;
               else
                  pz=11-pz;
               CHECK_PZ10;
            }

            /* Methode A */
#if DEBUG>0
      case 1086:
         if(retvals){
            retvals->methode="86a";
            retvals->pz_methode=1086;
         }
#endif
#ifdef __ALPHA
            pz =  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz =(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

            MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Methode B */
#if DEBUG>0
      case 2086:
         if(retvals){
            retvals->methode="86b";
            retvals->pz_methode=2086;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 87 +§§§4 */
/*
 * ######################################################################
 * #          Berechnung nach der Methode 87 (geändert zum 6.9.04)      #
 * ######################################################################
 * # Ausnahme:                                                          #
 * # Ist nach linksbündiger Auffüllung mit Nullen auf 10 Stellen die    #
 * # 3. Stelle der Kontonummer = 9 (Sachkonten), so erfolgt die         #
 * # Berechnung gemäß der Ausnahme in Methode 51 mit den                #
 * # gleichen Ergebnissen und Testkontonummern.                         #
 * #                                                                    #
 * # Methode A:                                                         #
 * # Vorgegebener Pascalcode, anzuwenden auf Stellen 5 bis 9            #
 * # von links der Kontonummer, Prüfziffer in Stelle 10.                #
 * # Der vorgegebener Pseudocode (pascal-ähnlich) wurde nach C          #
 * # umgeschrieben. Eine Beschreibung des Berechnungsverfahrens findet  #
 * # sich in der Datei pz<mmyy>.pdf (z.B. pz0602.pdf) der  Deutschen    #
 * # Bundesbank.                                                        #
 * #                                                                    #
 * # Methode B:                                                         #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6                               #
 * # Die für die Berechnung relevanten Stellen werden von rechts        #
 * # nach links mit den Ziffern 2, 3, 4, 5, 6 multipliziert. Die        #
 * # weitere Berechnung und die möglichen Ergebnisse entsprechen dem    #
 * # Verfahren 33.                                                      #
 * # Führt die Berechnung nach Methode B wiederum zu einem              #
 * # Prüfzifferfehlen, ist eine weitere Berechnung nach Methode C       #
 * # vorzunehmen.                                                       #
 * #                                                                    #
 * # Methode C:                                                         #
 * # Modulus 7, Gewichtung 2, 3, 4, 5, 6                                #
 * # Die Stellen 5 bis 9 der Kontonummer werden von rechts nach         #
 * # links mit den Gewichten multipliziert. Die jeweiligen Produkte     #
 * # werden addiert. Die Summe ist durch 7 zu dividieren. Der           #
 * # verbleibende Rest wird vom Divisor (7) subtrahiert. Das            #
 * # Ergebnis ist die Prüfziffer. Verbleibt nach der Division kein      #
 * # Rest, ist die Prüfziffer = 0.                                      #
 * ######################################################################
 */

      case 87:

                /* Ausnahme, Variante 1 */
         if(*(kto+2)=='9'){   /* Berechnung wie in Verfahren 51 */
#if DEBUG>0
      case 4087:
         if(retvals){
            retvals->methode="87d";
            retvals->pz_methode=4087;
         }
#endif
            pz =         9 * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

            /* Ausnahme, Variante 2 */
#if DEBUG>0
      case 5087:
         if(retvals){
            retvals->methode="87e";
            retvals->pz_methode=5087;
         }
#endif
               pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               +            9 * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

               MOD_11_352;   /* pz%=11 */
               if(pz<=1)
                  pz=0;
               else
                  pz=11-pz;
               CHECK_PZ10;
            }

#if DEBUG>0
      case 1087:
         if(retvals){
            retvals->methode="87a";
            retvals->pz_methode=1087;
         }
#endif
            /* Der Startindex für das Array konto[] ist 1, nicht wie in C
             * üblich 0; daher hat das es auch 11 Elemente (nicht wie in der
             * Beschreibung angegeben 10). Daß das so ist, sieht man an der
             * Initialisierung von i mit 4, an der Schleife [while(i<10)]
             * sowie am Ende des Verfahrens, wo p mit konto[10] verglichen
             * wird.
             * Konsequenterweise werden die beiden Arrays tab1 und tab2
             * mit dem Startindex 0 eingeführt ;-(((.
             */

         for(i=1,ptr=kto;i<11;)konto[i++]= *ptr++-'0';
         i=4;
         while(konto[i]==0)i++;
         c2=i%2;
         d2=0;
         a5=0;

         while(i<10){
            switch(konto[i]){
               case 0: konto[i]= 5; break;
               case 1: konto[i]= 6; break;
               case 5: konto[i]=10; break;
               case 6: konto[i]= 1; break;
            }

            if(c2==d2){
               if(konto[i]>5){
                  if(c2==0 && d2==0){
                     c2=d2=1;
                     a5=a5+6-(konto[i]-6);
                  }
                  else{
                     c2=d2=0;
                     a5=a5+konto[i];
                  }
               }
               else{
                  if(c2==0 && d2==0){
                     c2=1;
                     a5=a5+konto[i];
                  }
                  else{
                     c2=0;
                     a5=a5+konto[i];
                  }
               }
            }
            else{
               if(konto[i]>5){
                  if(c2==0){
                     c2=1;
                     d2=0;
                     a5=a5-6+(konto[i]-6);
                  }
                  else{
                     c2=0;
                     d2=1;
                     a5=a5-konto[i];
                  }
               }
               else{
                  if(c2==0){
                     c2=1;
                     a5=a5-konto[i];
                  }
                  else{
                     c2=0;
                     a5=a5-konto[i];
                  }
               }
            }
            i++;
         }
         while(a5<0 || a5>4){
            if(a5>4)
               a5=a5-5;
            else
               a5=a5+5;
         }
         if(d2==0)
            p=tab1[a5];
         else
            p=tab2[a5];
         if(p==konto[10])
            return OK; /* Prüfziffer ok; */
         else{
            if(konto[4]==0){
               if(p>4)
                  p=p-5;
               else
                  p=p+5;
               if(p==konto[10])return OK; /* Prüfziffer ok; */
            }
         }

            /* Methode B: Verfahren 33 */
#if DEBUG>0
      case 2087:
         if(retvals){
            retvals->methode="87b";
            retvals->pz_methode=2087;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode C: Verfahren 84 Variante 2 */
#if DEBUG>0
      case 3087:
         if(retvals){
            retvals->methode="87c";
            retvals->pz_methode=3087;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_7_112;   /* pz%=7 */
         if(pz)pz=7-pz;
#if DEBUG>0
         if(retvals){
            retvals->pz=pz;
            retvals->pz_pos=10;
         }
#endif
         if(pz==*(kto+9)-'0')
            return OK;
         else
            return FALSE;


/*  Berechnung nach der Methode 88 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 88                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7.                           #
 * # Die Stellen 4 bis 9 werden von rechts nach links mit den           #
 * # Gewichten 2, 3, 4, 5, 6, 7 multipliziert. Die weitere Berechnung   #
 * # entspricht dem Verfahren 06.                                       #
 * # Ausnahme: Ist die 3. Stelle der Kontonummer = 9, so werden         #
 * # die Stellen 3 bis 9 von rechts nach links mit den Gewichten        #
 * # 2, 3, 4, 5, 6, 7, 8 multipliziert.                                 #
 * ######################################################################
 */
      case 88:
#if DEBUG>0
         if(retvals){
            retvals->methode="88";
            retvals->pz_methode=88;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;
         if(kto[2]=='9')pz+= 9*8;   /* Ausnahme */

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 89 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 89                        #
 * ######################################################################
 * # 8- und 9-stellige Kontonummern sind mit dem                        #
 * # Berechnungsverfahren 10 zu prüfen.                                 #
 * #                                                                    #
 * # 7-stellige Kontonummern sind wie folgt zu prüfen:                  #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * # Die Kontonummer ist durch linksbündige Nullenauffüllung            #
 * # 10-stellig darzustellen. Die für die Berechnung relevante          #
 * # 6-stellige Stammnummer (x) befindet sich in den Stellen 4 bis      #
 * # 9, die Prüfziffer in Stelle 10 der Kontonummer. Die einzelnen      #
 * # Stellen der Stammnummer sind von rechts nach links mit den         #
 * # Ziffern 2, 3, 4, 5, 6, 7 zu multiplizieren. Die jeweiligen         #
 * # Produkte werden addiert, nachdem jeweils aus den 2- stelligen      #
 * # Produkten Quersummen gebildet wurden. Die Summe ist durch 11       #
 * # zu dividieren. Die weiteren Berechnungen und Ergebnisse            #
 * # entsprechen dem Verfahren 06.                                      #
 * #                                                                    #
 * # 1- bis 6- und 10-stellige Kontonummern sind nicht zu               #
 * # prüfen, da diese keine Prüfziffer enthalten.                       #
 * # Testkontonummern: 1098506, 32028008, 218433000                     #
 * ######################################################################
 */
      case 89:

            /* 8- und 9-stellige Kontonummern: Verfahren 10 */
#if DEBUG>0
      case 1089:
         if(retvals){
            retvals->methode="89a";
            retvals->pz_methode=1089;
         }
#endif
         if(*kto=='0' && (*(kto+1)!='0' || *(kto+2)!='0')){
            pz = (kto[1]-'0') * 9
               + (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_352;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

            /* 7-stellige Kontonummern */
#if DEBUG>0
      case 2089:
         if(retvals){
            retvals->methode="89b";
            retvals->pz_methode=2089;
         }
#endif
         if(*kto=='0' && *(kto+1)=='0' && *(kto+2)=='0' && *(kto+3)!='0'){
            pz=(kto[3]-'0')*7;
            if(pz>=40){
               if(pz>=50){
                  if(pz>=60)
                     pz-=54;
                  else
                     pz-=45;
               }
               else
                  pz-=36;
            }
            else if(pz>=20){
               if(pz>=30)
                  pz-=27;
               else
                  pz-=18;
            }
            else if(pz>=10)
               pz-=9;


            p1=(kto[4]-'0')*6;
            if(p1>=40){
               if(p1>=50)
                  p1-=45;
               else
                  p1-=36;
            }
            else if(p1>=20){
               if(p1>=30)
                  p1-=27;
               else
                  p1-=18;
            }
            else if(p1>=10)
               p1-=9;
            pz+=p1;

            p1=(kto[5]-'0')*5;
            if(p1>=40)
               p1-=36;
            else if(p1>=20){
               if(p1>=30)
                  p1-=27;
               else
                  p1-=18;
            }
            else if(p1>=10)
               p1-=9;
            pz+=p1;

            p1=(kto[6]-'0')*4;
            if(p1>=20){
               if(p1>=30)
                  p1-=27;
               else
                  p1-=18;
            }
            else if(p1>=10)
               p1-=9;
            pz+=p1;

            p1=(kto[7]-'0')*3;
            if(p1>=20)
               p1-=18;
            else if(p1>=10)
               p1-=9;
            pz+=p1;

            p1 = (kto[8]-'0') * 2;
            if(p1>=10)p1-=9;
            pz+=p1;

            MOD_11_44;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

            /* 1- bis 6- und 10-stellige Kontonummern */
#if DEBUG>0
      case 3089:
         if(retvals){
            retvals->methode="89c";
            retvals->pz_methode=3089;
         }
#endif
#if BAV_KOMPATIBEL
         return BAV_FALSE;
#else
         return OK_NO_CHK;
#endif


/* Berechnungsmethoden 90 bis 99 +§§§3
   Berechnung nach der Methode 90 +§§§4 */
/*
 * ######################################################################
 * #      Berechnung nach der Methode 90 (geändert zum 9.6.2014)        #
 * ######################################################################
 * # Die Kontonummer ist immer 10-stellig, ggf. ist die Kontonummer     #
 * # durch linksbündige Auffüllung mit Nullen 10-stellig                #
 * # darzustellen. Die Stelle 10 der Kontonummer ist per Definition     #
 * # die Prüfziffer. Kontonummern, die nach Durchführung der unten      #
 * # näher aufgeführten Berechnungsmethoden nicht zu einem richtigen    #
 * # Ergebnis führen, sind nicht gültig.                                #
 * #                                                                    #
 * # Die für die Berechnung relevante Kundennummer (K) befindet sich    #
 * # bei der Methode A und G in den Stellen 4 bis 9 der Kontonummer     #
 * # und bei den Methoden B bis E in den Stellen 5 bis 9.               #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist nach linksbündigem Auffüllen mit Nullen auf 10 Stellen die     #
 * # 3. Stelle der Kontonummer = 9 (Sachkonten) befindet sich die für   #
 * # die Berechnung relevante Sachkontonummer (S) in den Stellen 3      #
 * # bis 9. Diese Kontonummern sind ausschließlich nach Methode F zu    #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Kundenkonten                                                       #
 * # Kundenkonten haben im Gegensatz zu Sachkonten an der Stelle 3      #
 * # nicht die Ziffer 9 stehen.                                         #
 * #                                                                    #
 * # Ergibt die Berechnung der Prüfziffer nach dem Verfahren A einen    #
 * # Prüfzifferfehler, so sind weitere Berechnungen mit den Methoden    #
 * # B bis E und G vorzunehmen. kundenkontonummern, die nach            #
 * # Durchführung aller Berechnungsmethoden A bis E und G nicht zu      #
 * # einem richtigen Ergebnis führen, ist nicht gültig.                 #
 * #                                                                    #
 * # Methode A:                                                         #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * # Stellennr.: 1 2 3 4 5 6 7 8 9 A (A = 10)                           #
 * # Kontonr.: x x x K K K K K K P                                      #
 * # Gewichtung: 7 6 5 4 3 2                                            #
 * #                                                                    #
 * # Die Berechnung und mögliche Ergebnisse entsprechen dem Verfahren   #
 * # 06.                                                                #
 * #                                                                    #
 * # Methode B                                                          #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6                               #
 * # Stellennr.: 1 2 3 4 5 6 7 8 9 A (A = 10)                           #
 * # Kontonr.: x x x x K K K K K P                                      #
 * # Gewichtung: 6 5 4 3 2                                              #
 * #                                                                    #
 * # Die Berechnung und die möglichen Ergebnisse entsprechen dem        #
 * # Verfahren 06.                                                      #
 * #                                                                    #
 * # Methode C                                                          #
 * # Modulus 7, Gewichtung 2, 3, 4, 5, 6                                #
 * # Stellennr.: 1 2 3 4 5 6 7 8 9 A (A = 10)                           #
 * # Kontonr.: x x x x K K K K K P                                      #
 * # Gewichtung: 6 5 4 3 2                                              #
 * #                                                                    #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach links   #
 * # mit den Gewichten zu multiplizieren. Die jeweiligen Produkte       #
 * # werden addiert. Die Summe der Produkte ist durch 7 zu              #
 * # dividieren. Der verbleibende Rest wird vom Divisor (7)             #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt kein       #
 * # Rest, ist die Prüfziffer 0.                                        #
 * #                                                                    #
 * # Kontonummern, die in der Stelle 10 die Werte 7, 8 oder 9 haben,    #
 * # sind nach dieser Methode nicht gültig.                             #
 * #                                                                    #
 * # Methode D                                                          #
 * # Modulus 9, Gewichtung 2, 3, 4, 5, 6                                #
 * # Stellennr.: 1 2 3 4 5 6 7 8 9 A (A = 10)                           #
 * # Kontonr.:   x x x x K K K K K P                                    #
 * # Gewichtung:         6 5 4 3 2                                      #
 * #                                                                    #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach links   #
 * # mit den Gewichten zu multiplizieren. Die jeweiligen Produkte       #
 * # werden addiert. Die Summe der Produkte ist durch 9 zu              #
 * # dividieren. Der verbleibende Rest wird vom Divisor (9)             #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt kein       #
 * # Rest, ist die Prüfziffer 0.                                        #
 * #                                                                    #
 * # Kontonummern, die an der Stelle 10 den Wert 9 haben sind nach      #
 * # dieser Methode nicht gültig.                                       #
 * #                                                                    #
 * # Methode E                                                          #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2                               #
 * # Stellennr.: 1 2 3 4 5 6 7 8 9 A (A = 10)                           #
 * # Kontonr.:   x x x x K K K K K P                                    #
 * # Gewichtung:         2 1 2 1 2                                      #
 * #                                                                    #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach links   #
 * # mit den Gewichten zu multiplizieren. Die jeweiligen Produkte       #
 * # werden addiert. Die Summe der Produkte ist durch 10 zu             #
 * # dividieren. Der verbleibende Rest wird vom Divisor (10)            #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt kein       #
 * # Rest, ist die Prüfziffer 0.                                        #
 * #                                                                    #
 * # Methode G                                                          #
 * # Modulus 7, Gewichtung 2, 1, 2, 1, 2, 1                             #
 * # Stellennr.: 1 2 3 4 5 6 7 8 9 A (A = 10)                           #
 * # Kontonr.:   x x x K K K K K K P                                    #
 * # Gewichtung:       1 2 1 2 1 2                                      #
 * #                                                                    #
 * # Die einzelnen Stellen der Kontonummer sind von rechts nach links   #
 * # mit den Gewichten zu multiplizieren. Die jeweiligen Produkte       #
 * # werden addiert. Die Summe der Produkte ist durch 7 zu              #
 * # dividieren. Der verbleibende Rest wird vom Divisor (7)             #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer. Verbleibt kein       #
 * # Rest, ist die Prüfziffer 0.                                        #
 * #                                                                    #
 * # Sachkonten                                                         #
 * # Sachkonten haben im Gegensatz zu Kundenkonten an der Stelle 3      #
 * # die Ziffer 9 stehen.                                               #
 * #                                                                    #
 * # Methode F                                                          #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8                         #
 * # Stellennr.: 1 2 3 4 5 6 7 8 9 A (A = 10)                           #
 * # Kontonr.:   x x S S S S S S S P                                    #
 * # Gewichtung:     8 7 6 5 4 3 2                                      #
 * #                                                                    #
 * # Die Berechnung und die möglichen Ergebnisse entsprechen dem        #
 * # Verfahren 06. Es ist jedoch die vorgenannte Gewichtung zu          #
 * # beachten.                                                          #
 * ######################################################################
 */

      case 90:

            /* Sachkonto */
         if(*(kto+2)=='9'){ /* geändert zum 6.6.2005; vorher waren 3. und 4. Stelle 9 */
#if DEBUG>0
      case 6090:
         if(retvals){
            retvals->methode="90f";
            retvals->pz_methode=6090;
         }
#endif
         pz =      9       * 8 /* immer 9; kann vom Compiler optimiert werden */
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

            /* Methode A */
#if DEBUG>0
      case 1090:
         if(retvals){
            retvals->methode="90a";
            retvals->pz_methode=1090;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode B */
#if DEBUG>0
      case 2090:
         if(retvals){
            retvals->methode="90b";
            retvals->pz_methode=2090;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode C */
#if DEBUG>0
      case 3090:
         if(retvals){
            retvals->methode="90c";
            retvals->pz_methode=3090;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_7_112;   /* pz%=7 */
         if(pz)pz=7-pz;
         CHECK_PZX10;

            /* Methode D */
#if DEBUG>0
      case 4090:
         if(retvals){
            retvals->methode="90d";
            retvals->pz_methode=4090;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_9_144;   /* pz%=9 */
         if(pz)pz=9-pz;
         CHECK_PZX10;

            /* Methode E */
#if DEBUG>0
      case 5090:
         if(retvals){
            retvals->methode="90e";
            retvals->pz_methode=5090;
         }
#endif
         pz = (kto[4]-'0') * 2
            + (kto[5]-'0')
            + (kto[6]-'0') * 2
            + (kto[7]-'0')
            + (kto[8]-'0') * 2;

         MOD_10_40;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Methode G */
#if DEBUG>0
      case 7090:
         if(retvals){
            retvals->methode="90g";
            retvals->pz_methode=7090;
         }
#endif
         if(pz_aenderungen_aktivieren){
            pz = (kto[3]-'0')
               + (kto[4]-'0') * 2
               + (kto[5]-'0')
               + (kto[6]-'0') * 2
               + (kto[7]-'0')
               + (kto[8]-'0') * 2;

            MOD_7_56;    /* pz%=7 */
            if(pz)pz=7-pz;
            CHECK_PZ10;
         }
         else{
#if DEBUG>0
            if(!pz_aenderungen_aktivieren){  /* switch-code derzeit noch nicht gültig */
               if(untermethode==7)return UNDEFINED_SUBMETHOD;
               if(retvals){ /* Methode zurücksetzen, nicht definiert */
                  retvals->methode="90e";
                  retvals->pz_methode=5090;
               }
            }
#endif
            return FALSE;
         }

/*  Berechnung nach der Methode 91 +§§§4 */
/*
 * ######################################################################
 * #   Berechnung nach der Methode 91 (geändert zum 8.12.03)            #
 * ######################################################################
 * # 1. Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                         #
 * # 2. Modulus 11, Gewichtung 7, 6, 5, 4, 3, 2                         #
 * # 3. Modulus 11, Gewichtung 2, 3, 4, 0, 5, 6, 7, 8, 9, A (A = 10)    #
 * # 4. Modulus 11, Gewichtung 2, 4, 8, 5, 10, 9                        #
 * #                                                                    #
 * # Gemeinsame Hinweise für die Berechnungsvarianten 1 bis 4:          #
 * #                                                                    #
 * # Die Kontonummer ist immer 10-stellig. Die einzelnen Stellen        #
 * # der Kontonummer werden von links nach rechts von 1 bis 10          #
 * # durchnummeriert. Die Stelle 7 der Kontonummer ist die              #
 * # Prüfziffer. Die für die Berechnung relevanten Kundennummern        #
 * # (K) sind von rechts nach links mit den jeweiligen Gewichten zu     #
 * # multiplizieren. Die restliche Berechnung und möglichen             #
 * # Ergebnisse entsprechen dem Verfahren 06.                           #
 * #                                                                    #
 * # Ergibt die Berechnung nach der ersten beschriebenen Variante       #
 * # einen Prüfzifferfehler, so sind in der angegebenen Reihenfolge     #
 * # weitere Berechnungen mit den anderen Varianten                     #
 * # vorzunehmen, bis die Berechnung keinen Prüfzifferfehler mehr       #
 * # ergibt. Kontonummern, die endgültig nicht zu einem richtigen       #
 * # Ergebnis führen, sind nicht prüfbar.                               #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * # Die Stellen 8 bis 10 werden nicht in die Berechnung                #
 * # einbezogen.                                                        #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 7, 6, 5, 4, 3, 2                            #
 * # Die Stellen 8 bis 10 werden nicht in die Berechnung                #
 * # einbezogen.                                                        #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 0, 5, 6, 7, 8, 9, A (A = 10)       #
 * # Die Stellen 1 bis 10 werden in die Berechnung einbezogen.          #
 * #                                                                    #
 * # Variante 4:                                                        #
 * # Modulus 11, Gewichtung 2, 4, 8, 5, A, 9 (A = 10)                   #
 * # Die Stellen 8 bis 10 werden nicht in die Berechnung einbezogen.    #
 * ######################################################################
 */
      case 91:

            /* Methode A */
#if DEBUG>0
      case 1091:
         if(retvals){
            retvals->methode="91a";
            retvals->pz_methode=1091;
         }
#endif
         pz = (kto[0]-'0') * 7
            + (kto[1]-'0') * 6
            + (kto[2]-'0') * 5
            + (kto[3]-'0') * 4
            + (kto[4]-'0') * 3
            + (kto[5]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX7;

            /* Methode B */
#if DEBUG>0
      case 2091:
         if(retvals){
            retvals->methode="91b";
            retvals->pz_methode=2091;
         }
#endif
         pz = (kto[0]-'0') * 2
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 4
            + (kto[3]-'0') * 5
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 7;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX7;

            /* Methode C */
#if DEBUG>0
      case 3091:
         if(retvals){
            retvals->methode="91c";
            retvals->pz_methode=3091;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[7]-'0') * 4
            + (kto[8]-'0') * 3
            + (kto[9]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX7;

            /* Methode D */
#if DEBUG>0
      case 4091:
         if(retvals){
            retvals->methode="91d";
            retvals->pz_methode=4091;
         }
#endif
         pz = (kto[0]-'0') * 9
            + (kto[1]-'0') * 10
            + (kto[2]-'0') * 5
            + (kto[3]-'0') * 8
            + (kto[4]-'0') * 4
            + (kto[5]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ7;

/*  Berechnung nach der Methode 92 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 92                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 3, 7, 1, 3, 7, 1.                           #
 * # Die Berechnung erfolgt wie bei Verfahren 01, jedoch werden nur     #
 * # die Stellen 4 bis 9 einbezogen. Stelle 10 ist die Prüfziffer.      #
 * ######################################################################
 */
      case 92:
#if DEBUG>0
         if(retvals){
            retvals->methode="92";
            retvals->pz_methode=92;
         }
#endif
         pz = (kto[3]-'0')
            + (kto[4]-'0') * 7
            + (kto[5]-'0') * 3
            + (kto[6]-'0')
            + (kto[7]-'0') * 7
            + (kto[8]-'0') * 3;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 93 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 93                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6.                              #
 * # Die für die Berechnung relevante Kundennummer befindet sich        #
 * # entweder                                                           #
 * # a) in den Stellen 1 bis 5, die Prüfziffer in Stelle  6,            #
 * # b) in den Stellen 5 bis 9, die Prüfziffer in Stelle 10.            #
 * # Die 2-stellige Unternummer und die 2-stellige Kontoartnummer       #
 * # werden nicht in die Berechnung einbezogen. Sie befinden sich im    #
 * # Fall a) an Stelle 7 bis 10. Im Fall b) befinden Sie sich an        #
 * # Stelle 1 bis 4 und müssen "0000" lauten.                           #
 * # Die 5-stellige Kundennummer wird von rechts nach links mit den     #
 * # Gewichten multipliziert. Die weitere Berechnung und die            #
 * # möglichen Ergebnisse entsprechen dem Verfahren 06.                 #
 * # Führt die Berechnung zu einem Prüfziffernfehler, so ist die        #
 * # Berechnung nach Variante 2 vorzunehmen. Das Berechnungsverfahren   #
 * # entspricht Variante 1. Die Summe der Produkte ist jedoch durch     #
 * # 7 zu dividieren. Der verbleibende Rest wird vom Divisor (7)        #
 * # subtrahiert. Das Ergebnis ist die Prüfziffer.                      #
 * ######################################################################
 */
      case 93:

            /* Variante 1 */
         if(*kto=='0' && *(kto+1)=='0' && *(kto+2)=='0' && *(kto+3)=='0'){   /* Fall b) */
#if DEBUG>0
      case 2093:
         if(retvals){
            retvals->methode="93b";
            retvals->pz_methode=2093;
         }
#endif
            pz = (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            p1=pz;
            MOD_11_176;   /* pz%=11 */
         }
         else{
#if DEBUG>0
      case 1093:
         if(retvals){
            retvals->methode="93a";
            retvals->pz_methode=1093;
         }
#endif
            pz = (kto[0]-'0') * 6
               + (kto[1]-'0') * 5
               + (kto[2]-'0') * 4
               + (kto[3]-'0') * 3
               + (kto[4]-'0') * 2;

            kto[9]=kto[5];  /* Prüfziffer nach Stelle 10 */
            p1=pz;
            MOD_11_176;   /* pz%=11 */
         }
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Variante 2 */
#if DEBUG>0
            /* nicht optimiert, da dieser Teil nur in der DEBUG-Version benutzt wird */

         if(untermethode){ /* pz wurde noch nicht berechnet */
            if(*kto=='0' && *(kto+1)=='0' && *(kto+2)=='0' && *(kto+3)=='0'){   /* Fall b) */
#if DEBUG>0
      case 4093:
         if(retvals){
            retvals->methode="93d";
            retvals->pz_methode=4093;
         }
#endif
               for(p1=0,ptr=kto+8,i=0;i<5;ptr--,i++)
                  p1+=(*ptr-'0')*w93[i];
            }
            else{
#if DEBUG>0
      case 3093:
         if(retvals){
            retvals->methode="93c";
            retvals->pz_methode=3093;
         }
#endif
               for(p1=0,ptr=kto+4,i=0;i<5;ptr--,i++)
                  p1+=(*ptr-'0')*w93[i];
                  *(kto+9)= *(kto+5);  /* Prüfziffer nach Stelle 10 */
            }
         }
#endif
         pz=p1%7;
         if(pz)pz=7-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 94 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 94                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 1, 2, 1, 2, 1, 2, 1, 2, 1.                  #
 * # Die Stellen 1 bis 9 der Kontonummer sind von rechts nach links     #
 * # mit den Gewichten zu multiplizieren. Die weitere Berechnung        #
 * # erfolgt wie bei Verfahren 00.                                      #
 * ######################################################################
 */
      case 94:
#if DEBUG>0
         if(retvals){
            retvals->methode="94";
            retvals->pz_methode=94;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[0]-'0')
            + ((kto[1]<'5') ? (kto[1]-'0')*2 : (kto[1]-'0')*2-9)
            +  (kto[2]-'0')
            + ((kto[3]<'5') ? (kto[3]-'0')*2 : (kto[3]-'0')*2-9)
            +  (kto[4]-'0')
            + ((kto[5]<'5') ? (kto[5]-'0')*2 : (kto[5]-'0')*2-9)
            +  (kto[6]-'0')
            + ((kto[7]<'5') ? (kto[7]-'0')*2 : (kto[7]-'0')*2-9)
            +  (kto[8]-'0');
#else
         pz =(kto[0]-'0')+(kto[2]-'0')+(kto[4]-'0')+(kto[6]-'0')+(kto[8]-'0');
         if(kto[1]<'5')pz+=(kto[1]-'0')*2; else pz+=(kto[1]-'0')*2-9;
         if(kto[3]<'5')pz+=(kto[3]-'0')*2; else pz+=(kto[3]-'0')*2-9;
         if(kto[5]<'5')pz+=(kto[5]-'0')*2; else pz+=(kto[5]-'0')*2-9;
         if(kto[7]<'5')pz+=(kto[7]-'0')*2; else pz+=(kto[7]-'0')*2-9;
#endif

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 95 +§§§4 */
/*
 * ######################################################################
 * #      Berechnung nach der Methode 95 (geändert zum 9.9.2013)        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #
 * # Die Berechnung erfolgt wie bei Verfahren 06.                       #
 * # Ausnahmen:                                                         #
 * # Kontonr.: 0000000001 bis 0001999999                                #
 * # Kontonr.: 0009000000 bis 0025999999                                #
 * # Kontonr.: 0396000000 bis 0499999999                                #
 * # Kontonr.: 0700000000 bis 0799999999                                #
 * # Kontonr.: 0910000000 bis 0989999999 (ab 9.9.2013)                  #
 * # Für diese Kontonummernkreise ist keine Prüfzifferberechnung        #
 * # möglich. Sie sind als richtig anzusehen.                           #
 * ######################################################################
 */
      case 95:
#if DEBUG>0
         if(retvals){
            retvals->methode="95";
            retvals->pz_methode=95;
         }
#endif
        tmp=b4[I kto[0]]+b3[I kto[1]]+b2[I kto[2]]+b1[I kto[3]];
        if(   /* Ausnahmen: keine Prüfzifferberechnung */
                              tmp<=1  /* Konto 0 wird vorher als ungültig abgefangen */
              || (tmp>=9   && tmp<=25)
              || (tmp>=396 && tmp<=499)
              || (tmp>=700 && tmp<=799)
              || (tmp>=910 && tmp<=989)
          )return OK_NO_CHK;
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 96 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 96                        #
 * ######################################################################
 * # A. Modulus 11, Gewichtung 2,3,4,5,6,7,8,9,1                        #
 * # B. Modulus 10, Gewichtung 2,1,2,1,2,1,2,1,2                        #
 * # Die Prüfziffernberechnung ist nach Kennziffer 19 durchzuführen.    #
 * # Führt die Berechnung zu einem Fehler, so ist sie nach Kennziffer   #
 * # 00 durchzuführen. Führen beide Varianten zu einem Fehler, so       #
 * # gelten Kontonummern zwischen 0001300000 und 0099399999 als         #
 * # richtig.                                                           #
 * ######################################################################
 */
      case 96:

#if DEBUG>0
      case 3096:
         if(retvals){
            retvals->methode="96c";
            retvals->pz_methode=3096;
         }
#endif
            /* die Berechnung muß in diesem Fall nicht gemacht werden */
         if(strcmp(kto,"0001300000")>=0 && strcmp(kto,"0099400000")<0)
            return OK_NO_CHK;

            /* Methode A */
#if DEBUG>0
      case 1096:
         if(retvals){
            retvals->methode="96a";
            retvals->pz_methode=1096;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode B */
#if DEBUG>0
      case 2096:
         if(retvals){
            retvals->methode="96b";
            retvals->pz_methode=2096;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_10_80;   /* pz%=11 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 97 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 97                        #
 * ######################################################################
 * #  Modulus 11:                                                       #
 * #  Die Kontonummer (5, 6, 7, 8, 9 o. 10-stellig) ist durch links-    #
 * #  bündige Nullenauffüllung 10-stellig darzustellen. Danach ist die  #
 * #  10. Stelle die Prüfziffer.                                        #
 * #                                                                    #
 * #  Die Kontonummer ist unter Weglassung der Prüfziffer (= Wert X)    #
 * #  durch 11 zu teilen. Das Ergebnis der Division ist ohne die        #
 * #  Nachkomma-Stellen mit 11 zu multiplizieren. Das Produkt ist vom   #
 * #  'Wert X' zu subtrahieren.                                         #
 * #                                                                    #
 * #  Ist das Ergebnis < 10, so entspricht das Ergebnis der Prüfziffer. #
 * #  Ist das Ergebnis = 10, so ist die Prüfziffer = 0                  #
 * ######################################################################
 */

      case 97:
#if DEBUG>0
         if(retvals){
            retvals->methode="97";
            retvals->pz_methode=97;
         }
#endif
         if(kto[0]=='0' && kto[1]=='0' && kto[2]=='0' && kto[3]=='0' && kto[4]=='0'
               && kto[5]=='0')return INVALID_KTO;

         p1= *(kto+9);
         *(kto+9)=0;    /* Prüfziffer (temporär) löschen */
         pz=atoi(kto)%11;
         if(pz==10)pz=0;
         *(kto+9)=p1;   /* Prüfziffer wiederherstellen */
         CHECK_PZ10;

/*  Berechnung nach der Methode 98 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 98                        #
 * ######################################################################
 * # Modulus 10, Gewichtung 3, 1, 7, 3, 1, 7, 3                         #
 * # Die Kontonummer ist 10-stellig. Die Berechnung erfolgt wie         #
 * # bei Verfahren 01. Es ist jedoch zu beachten, dass nur die          #
 * # Stellen 3 bis 9 in die Prüfzifferberechnung einbezogen             #
 * # werden. Die Stelle 10 der Kontonummer ist die Prüfziffer.          #
 * # Führt die Berechnung zu einem falschen Ergebnis, so ist            #
 * # alternativ das Verfahren 32 anzuwenden.                            #
 * ######################################################################
 */
      case 98:
#if DEBUG>0
      case 1098:
         if(retvals){
            retvals->methode="98a";
            retvals->pz_methode=1098;
         }
#endif
         pz = (kto[2]-'0') * 3
            + (kto[3]-'0') * 7
            + (kto[4]-'0')
            + (kto[5]-'0') * 3
            + (kto[6]-'0') * 7
            + (kto[7]-'0')
            + (kto[8]-'0') * 3;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* alternativ: Verfahren 32 */
#if DEBUG>0
      case 2098:
         if(retvals){
            retvals->methode="98b";
            retvals->pz_methode=2098;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode 99 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode 99                        #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #
 * # Die Berechnung erfolgt wie bei Verfahren 06.                       #
 * # Ausnahmen: Kontonr.: 0396000000 bis 0499999999                     #
 * # Für diese Kontonummern ist keine Prüfzifferberechnung              #
 * # möglich.  Sie sind als richtig anzusehen.                          #
 * ######################################################################
 */
      case 99:
#if DEBUG>0
         if(retvals){
            retvals->methode="99";
            retvals->pz_methode=99;
         }
#endif
         if(strcmp(kto,"0396000000")>=0 && strcmp(kto,"0500000000")<0){
            pz= *(kto+9)-'0';
            return OK;
         }
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/* Berechnungsmethoden A0 bis A9 +§§§3
   Berechnung nach der Methode A0 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode A0                       #
 * ######################################################################
 * #  Modulus 11, Gewichtung 2, 4, 8, 5, 10, 0, 0, 0, 0 Die             #
 * #  Kontonummer ist einschließlich der Prüfziffer 10- stellig,        #
 * #  ggf. ist die Kontonummer für die Prüfzifferberechnung durch       #
 * #  linksbündige Auffüllung mit Nullen 10-stellig darzustellen.       #
 * #  Die Stelle 10 ist die Prüfziffer. Die einzelnen Stellen der       #
 * #  Kontonummer (ohne Prüfziffer) sind von rechts nach links mit      #
 * #  dem zugehörigen Gewicht (2, 4, 8, 5, 10, 0, 0, 0, 0) zu           #
 * #  multiplizieren. Die Produkte werden addiert. Das Ergebnis ist     #
 * #  durch 11 zu dividieren. Ergibt sich nach der Division ein         #
 * #  Rest von 0 oder 1, so ist die Prüfziffer 0. Ansonsten ist der     #
 * #  Rest vom Divisor (11) zu subtrahieren. Das Ergebnis ist die       #
 * #  Prüfziffer.                                                       #
 * #  Ausnahme: 3-stellige Kontonummern bzw. Kontonummern, deren        #
 * #  Stellen 1 bis 7 = 0 sind, enthalten keine Prüfziffer und sind     #
 * #  als richtig anzusehen.                                            #
 * ######################################################################
 */
      case 100:
#if DEBUG>0
         if(retvals){
            retvals->methode="A0";
            retvals->pz_methode=100;
         }
#endif
         if(!strncmp(kto,"0000000",7))return OK_NO_CHK;
         pz = (kto[4]-'0') * 10
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 8
            + (kto[7]-'0') * 4
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode A1 +§§§4 */
/*
 * ######################################################################
 * #    Berechnung nach der Methode A1 (geändert zum 9.6.2003)          #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 0, 0.                  #
 * #                                                                    #
 * # Die Kontonummern sind 8- oder 10-stellig. Kontonummern (ohne       #
 * # führende Nullen  gezählt) mit 9 oder weniger als 8 Stellen sind    #
 * # falsch. 8-stellige Kontonummern sind für die Prüfzifferberechnung  #
 * # durch linksbündige Auffüllung mit Nullen 10-stellig darzustellen.  #
 * # Die Berechnung erfolgt wie beim Verfahren 00.                      #
 * ######################################################################
 */

      case 101:
#if DEBUG>0
         if(retvals){
            retvals->methode="A1";
            retvals->pz_methode=101;
         }
#endif
         if((*kto=='0' && *(kto+1)!='0')
               || (*kto=='0' && *(kto+1)=='0' && *(kto+2)=='0'))
            return INVALID_KTO;
#ifdef __ALPHA
         pz = ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode A2 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode A2                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1: Gewichtung und Berechnung erfolgen nach der Methode 00.#
 * # Führt die Berechnung nach Variante 1 zu einem Prüfzifferfehler,    #
 * # so ist nach Variante 2 zu prüfen.                                  #
 * #                                                                    #
 * # Variante 2: Gewichtung und Berechnung erfolgen nach der Methode 04.#
 * ######################################################################
 */
      case 102:
#if DEBUG>0
      case 1102:
         if(retvals){
            retvals->methode="A2a";
            retvals->pz_methode=1102;
         }
#endif

            /* Variante 1: Berechnung nach Methode 00 */
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Variante 2: Berechnung nach Methode 04 */
#if DEBUG>0
      case 2102:
         if(retvals){
            retvals->methode="A2b";
            retvals->pz_methode=2102;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz)pz=11-pz;
         INVALID_PZ10;
         CHECK_PZ10;

/*  Berechnung nach der Methode A3 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode A3                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10                  #
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1: Gewichtung und Berechnung erfolgen nach der Methode 00.#
 * # Führt die Berechnung nach Variante 1 zu einem Prüfzifferfehler,    #
 * # so ist nach Variante 2 zu prüfen.                                  #
 * #                                                                    #
 * # Variante 2: Gewichtung und Berechnung erfolgen nach der Methode 10.#
 * ######################################################################
 */
      case 103:

            /* Variante 1: Berechnung nach Methode 00 */
#if DEBUG>0
      case 1103:
         if(retvals){
            retvals->methode="A3a";
            retvals->pz_methode=1103;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Variante 2: Berechnung nach Methode 10 */
#if DEBUG>0
      case 2103:
         if(retvals){
            retvals->methode="A3b";
            retvals->pz_methode=2103;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode A4 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode A4                       #
 * ######################################################################
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0                   #
 * # Modulus 7,  Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0                   #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 0, 0, 0, 0                   #
 * # Modulus 7,  Gewichtung 2, 3, 4, 5, 6, 0, 0, 0, 0                   #
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen. Zur    #
 * # Prüfung einer Kontonummer sind die folgenden Varianten zu          #
 * # rechnen. Dabei ist zu beachten, dass Kontonummern mit der          #
 * # Ziffernfolge 99 an den Stellen 3 und 4 (XX99XXXXXX) nur nach       #
 * # Variante 3 und ggf. 4 zu prüfen sind. Alle anderen Kontonummern    #
 * # sind nacheinander nach den Varianten 1, ggf. 2 und ggf. 4 zu       #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0                   #
 * #                                                                    #
 * # In die Prüfzifferberechnung werden nur die Stellen 4 bis 9         #
 * # einbezogen. Die Stelle 10 ist die Prüfziffer. Die weitere          #
 * # Berechnung erfolgt nach dem Verfahren 06.                          #
 * #                                                                    #
 * # Führt die Berechnung zu einem Fehler, ist nach Variante 2 zu       #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 7, Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0                    #
 * #                                                                    #
 * # Die Stellen 4 bis 9 der Kontonummer werden von rechts nach links   #
 * # mit den Gewichten multipliziert. Die jeweiligen Produkte werden    #
 * # addiert. Die Summe ist durch 7 zu dividieren. Der verbleibende     #
 * # Rest wird vom Divisor (7) subtrahiert. Das Ergebnis ist die        #
 * # Prüfziffer (Stelle 10). Verbleibt nach der Division kein Rest,     #
 * # ist die Prüfziffer 0.                                              #
 * #                                                                    #
 * # Führt die Berechnung zu einem Fehler, ist nach Variante 4 zu       #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 0, 0, 0, 0                   #
 * #                                                                    #
 * # In die Prüfzifferberechnung werden nur die Stellen 5 bis 9         #
 * # einbezogen. Die Stelle 10 ist die Prüfziffer. Die weitere          #
 * # Berechnung erfolgt nach dem Verfahren 06.                          #
 * #                                                                    #
 * # Führt die Berechnung zu einem Fehler, ist nach Variante 4 zu       #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Variante 4:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 0, 0, 0, 0                   #
 * # Modulus 7,  Gewichtung 2, 3, 4, 5, 6, 0, 0, 0, 0                   #
 * # Die Berechnung erfolgt nach der Methode 93.                        #
 * ######################################################################
 */

      case 104:
         if(*(kto+2)!='9' || *(kto+3)!='9'){

                /* Variante 1 */
#if DEBUG>0
      case 1104:
         if(retvals){
            retvals->methode="A4a";
            retvals->pz_methode=1104;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

                /* Variante 2 */
#if DEBUG>0
      case 2104:
         if(retvals){
            retvals->methode="A4b";
            retvals->pz_methode=2104;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_7_224;   /* pz%=7 */
            if(pz)pz=7-pz;
            CHECK_PZX10;
         }
         else{ /* 3. und 4. Stelle sind 9 */

                /* Variante 3 */
#if DEBUG>0
      case 3104:
         if(retvals){
            retvals->methode="A4c";
            retvals->pz_methode=3104;
         }
#endif
         pz = (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;
         }

            /* Variante 4: Methode 93, Variante 1 */
#if DEBUG>0
      case 4104:
         if(retvals){
            retvals->methode="A4d";
            retvals->pz_methode=4104;
         }
#endif
         if(*kto=='0' && *(kto+1)=='0' && *(kto+2)=='0' && *(kto+3)=='0'){   /* Fall b) */
            pz = (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            p1=pz;
            MOD_11_176;   /* pz%=11 */
         }
         else{
            pz = (kto[0]-'0') * 6
               + (kto[1]-'0') * 5
               + (kto[2]-'0') * 4
               + (kto[3]-'0') * 3
               + (kto[4]-'0') * 2;

            kto[9]=kto[5];  /* Prüfziffer nach Stelle 10 */
            p1=pz;
            MOD_11_176;   /* pz%=11 */
         }
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Methode 93, Variante 2 */
#if DEBUG>0
#if DEBUG>0
      case 5104:
         if(retvals){
            retvals->methode="A4e";
            retvals->pz_methode=5104;
         }
#endif
         if(untermethode){ /* pz wurde noch nicht berechnet */
            if(*kto=='0' && *(kto+1)=='0' && *(kto+2)=='0' && *(kto+3)=='0'){   /* Fall b) */
               for(p1=0,ptr=kto+8,i=0;i<5;ptr--,i++)
                  p1+=(*ptr-'0')*w93[i];
            }
            else{
               for(p1=0,ptr=kto+4,i=0;i<5;ptr--,i++)
                  p1+=(*ptr-'0')*w93[i];
                  *(kto+9)= *(kto+5);  /* Prüfziffer nach Stelle 10 */
            }
         }
#endif
         pz=p1%7;
         if(pz)pz=7-pz;
         CHECK_PZ10;
         break;

/*  Berechnung nach der Methode A5 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode A5                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10                  #
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1: Gewichtung und Berechnung erfolgen nach der Methode    #
 * # 00. Führt die Berechnung nach Variante 1 zu einem                  #
 * # Prüfzifferfehler, so sind 10-stellige Konten mit einer 9 an        #
 * # Stelle 1 falsch, alle anderen Konten sind nach Variante 2 zu       #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Variante 2: Gewichtung und Berechnung erfolgen nach der Methode 10.#
 * ######################################################################
 */
      case 105:
#if DEBUG>0
      case 1105:
         if(retvals){
            retvals->methode="A5a";
            retvals->pz_methode=1105;
         }
#endif
            /* Variante 1: Berechnung nach Methode 00 */
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;
         if(*kto=='9')return INVALID_KTO;

            /* Variante 2: Berechnung nach Methode 10 */
#if DEBUG>0
      case 2105:
         if(retvals){
            retvals->methode="A5b";
            retvals->pz_methode=2105;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode A6 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode A6                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Modulus 10, Gewichtung 3, 7, 1, 3, 7, 1, 3, 7, 1                   #
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10- stellig,     #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen. Die    #
 * # Stelle 10 ist die Prüfziffer.                                      #
 * #                                                                    #
 * # Sofern dann an der zweiten Stelle der Kontonummer eine 8 steht,    #
 * # erfolgen Gewichtung und Berechnung wie beim Verfahren 00.          #
 * #                                                                    #
 * # Bei allen Kontonummern, die keine 8 an der zweiten Stelle          #
 * # haben, erfolgen Gewichtung und Berechnung wie beim Verfahren 01.   #
 * ######################################################################
 */

      case 106:
         if(kto[1]=='8'){

                /* Variante 1 */
#if DEBUG>0
      case 1106:
         if(retvals){
            retvals->methode="A6a";
            retvals->pz_methode=1106;
         }
#endif
#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  8
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz=8+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }
         else{

                /* Variante 2 */
#if DEBUG>0
      case 2106:
         if(retvals){
            retvals->methode="A6b";
            retvals->pz_methode=2106;
         }
#endif
            pz = (kto[0]-'0')
               + (kto[1]-'0') * 7
               + (kto[2]-'0') * 3
               + (kto[3]-'0')
               + (kto[4]-'0') * 7
               + (kto[5]-'0') * 3
               + (kto[6]-'0')
               + (kto[7]-'0') * 7
               + (kto[8]-'0') * 3;

            MOD_10_160;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }

/*  Berechnung nach der Methode A7 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode A7                       #
 * ######################################################################
 * #  Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                  #
 * #                                                                    #
 * #  Die Kontonummer ist einschließlich der Prüfziffer 10- stellig,    #
 * #  ggf. ist die Kontonummer für die Prüfzifferberechnung durch       #
 * #  linksbündige Auffüllung mit Nullen 10-stellig darzustellen.       #
 * #                                                                    #
 * #  Variante 1:                                                       #
 * #  Gewichtung und Berechnung erfolgen nach der Methode 00. Führt die #
 * #  Berechnung nach Variante 1 zu einem Prüfzifferfehler, ist nach    #
 * #  Variante 2 zu prüfen.                                             #
 * #                                                                    #
 * #  Variante 2:                                                       #
 * #  Gewichtung und Berechnung erfolgen nach der Methode 03.           #
 * ######################################################################
 */

      case 107:

                /* Variante 1 */
#if DEBUG>0
      case 1107:
         if(retvals){
            retvals->methode="A7a";
            retvals->pz_methode=1107;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

                /* Variante 2 */
#if DEBUG>0
      case 2107:
         if(retvals){
            retvals->methode="A7b";
            retvals->pz_methode=2107;
         }
#endif
         pz = (kto[0]-'0') * 2
            + (kto[1]-'0')
            + (kto[2]-'0') * 2
            + (kto[3]-'0')
            + (kto[4]-'0') * 2
            + (kto[5]-'0')
            + (kto[6]-'0') * 2
            + (kto[7]-'0')
            + (kto[8]-'0') * 2;

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;


/*  Berechnung nach der Methode A8 +§§§4 */
/*
 * ######################################################################
 * #   Berechnung nach der Methode A8 (geändert zum 7.3.05)             #
 * ######################################################################
 * # Die Kontonummer ist durch linksbündige Nullenauffüllung 10-        #
 * # stellig darzustellen. Die 10. Stelle ist per Definition die        #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * # Die Stellen 4 bis 9 der Kontonummer werden von rechts nach links   #
 * # mit den Ziffern 2, 3, 4, 5, 6, 7 multipliziert. Die weitere        #
 * # Berechnung und die möglichen Ergebnisse entsprechen dem Verfahren  #
 * # 06. Führt die Berechnung nach Variante 1 zu einem Prüfziffer-      #
 * # fehler, so sind die Konten nach Variante 2 zu prüfen.              #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1                            #
 * # Die Stellen 4 bis 9 der Kontonummer werden von rechts nach links   #
 * # mit den Ziffern 2, 1, 2, 1, 2, 1 multipliziert. Die weiter         #
 * # Berechnung und die möglichen Ergebnisse entsprechen dem Verfahren  #
 * # 00.                                                                #
 * #                                                                    #
 * # Ausnahme:                                                          #
 * # Ist nach linksbündiger Auffüllung mit Nullen auf 10 Stellen die    #
 * # 3. Stelle der Kontonummer = 9 (Sachkonten), so erfolgt die         #
 * # Berechnung gemäß der Ausnahme in Methode 51 mit den gleichen       #
 * # Ergebnissen und Testkontonummern.                                  #
 * ######################################################################
 */

      case 108:

                /* Ausnahme, Variante 1 */
         if(*(kto+2)=='9'){   /* Berechnung wie in Verfahren 51 */
#if DEBUG>0
      case 3108:
         if(retvals){
            retvals->methode="A8c";
            retvals->pz_methode=3108;
         }
#endif
            pz =         9 * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

            /* Ausnahme, Variante 2 */
#if DEBUG>0
      case 4108:
         if(retvals){
            retvals->methode="A8d";
            retvals->pz_methode=4108;
         }
#endif
               pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               + (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

               MOD_11_352;   /* pz%=11 */
               if(pz<=1)
                  pz=0;
               else
                  pz=11-pz;
               CHECK_PZ10;
            }

#if DEBUG>0
      case 1108:
         if(retvals){
            retvals->methode="A8a";
            retvals->pz_methode=1108;
         }
#endif
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

                /* Variante 2 */
#if DEBUG>0
      case 2108:
         if(retvals){
            retvals->methode="A8b";
            retvals->pz_methode=2108;
         }
#endif
#ifdef __ALPHA
         pz =  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

         pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode A9 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode A9                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 3, 7, 1, 3, 7, 1, 3, 7, 1                   #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Gewichtung und Berechnung erfolgen nach der Methode 01. Führt die  #
 * # Berechnung nach Variante 1 zu einem Prüfzifferfehler, so ist nach  #
 * # Variante 2 zu prüfen.                                              #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Gewichtung und Berechnung erfolgen nach der Methode 06.            #
 * ######################################################################
 */

      case 109:

            /* Variante 1: Berechnung nach Methode 01 */
#if DEBUG>0
      case 1109:
         if(retvals){
            retvals->methode="A9a";
            retvals->pz_methode=1109;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 7
            + (kto[2]-'0') * 3
            + (kto[3]-'0')
            + (kto[4]-'0') * 7
            + (kto[5]-'0') * 3
            + (kto[6]-'0')
            + (kto[7]-'0') * 7
            + (kto[8]-'0') * 3;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Variante 2: Berechnung nach Methode 06 */
#if DEBUG>0
      case 2109:
         if(retvals){
            retvals->methode="A9b";
            retvals->pz_methode=2109;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/* Berechnungsmethoden B0 bis B9 +§§§3
   Berechnung nach der Methode B0 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B0                       #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummern sind immer 10-stellig. Kontonummern (ohne         #
 * # führende Nullen gezählt) mit 9 oder weniger Stellen sind falsch.   #
 * # Kontonummern mit 8 an der ersten Stelle sind ebenfalls falsch.     #
 * # Die weitere Verfahrensweise richtet sich nach der 8. Stelle der    #
 * # Kontonummer:                                                       #
 * #                                                                    #
 * # Variante 1                                                         #
 * #                                                                    #
 * # Für Kontonummern mit einer 1, 2, 3, oder 6 an der 8. Stelle gilt   #
 * # das Verfahren 09 (Keine Prüfzifferberechnung, alle Kontonummern    #
 * # sind richtig).                                                     #
 * #                                                                    #
 * # Variante 2                                                         #
 * #                                                                    #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #
 * #             (von rechts beginnend)                                 #
 * #                                                                    #
 * # Für Kontonummern mit einer 0, 4, 5, 7, 8 oder 9 an der 8. Stelle   #
 * # erfolgen Gewichtung und Berechnung wie beim Verfahren 06.          #
 * ######################################################################
 */

      case 110:
#if DEBUG>0
         if(retvals){
            retvals->methode="B0";
            retvals->pz_methode=110;
         }
#endif
         if(kto[0]=='0' || kto[0]=='8')return INVALID_KTO;

            /* Variante 1 */
         if(kto[7]=='1' || kto[7]=='2' || kto[7]=='3' || kto[7]=='6'){
#if DEBUG>0
      case 1110:
         if(retvals){
            retvals->methode="B0a";
            retvals->pz_methode=1110;
         }
#endif
            return OK_NO_CHK;
         }

            /* Variante 2 */
#if DEBUG>0
      case 2110:
         if(retvals){
            retvals->methode="B0b";
            retvals->pz_methode=2110;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode B1 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B1                       #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 7, 3, 1, 7, 3, 1, 7, 3, 1                   #
 * # Gewichtung und Berechnung erfolgen nach der Methode 05. Führt die  #
 * # Berechnung nach Variante 1 zu einem Prüfzifferfehler, so ist nach  #
 * # Variante 2 zu prüfen.                                              #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 3, 7, 1, 3, 7, 1, 3, 7, 1                   #
 * # Gewichtung und Berechnung erfolgen nach der Methode 01.            #
 * ######################################################################
 */

      case 111:

            /* Variante 1: Berechnung nach Methode 05 */
#if DEBUG>0
      case 1111:
         if(retvals){
            retvals->methode="B1a";
            retvals->pz_methode=1111;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 7
            + (kto[3]-'0')
            + (kto[4]-'0') * 3
            + (kto[5]-'0') * 7
            + (kto[6]-'0')
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 7;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Variante 2: Berechnung nach Methode 01 */
#if DEBUG>0
      case 2111:
         if(retvals){
            retvals->methode="B1b";
            retvals->pz_methode=2111;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 7
            + (kto[2]-'0') * 3
            + (kto[3]-'0')
            + (kto[4]-'0') * 7
            + (kto[5]-'0') * 3
            + (kto[6]-'0')
            + (kto[7]-'0') * 7
            + (kto[8]-'0') * 3;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode B2 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B2                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 2                   #
 * # Kontonummern, die an der 1. Stelle von links der 10- stelligen     #
 * # Kontonummer den Wert 0 bis 7 beinhalten, sind nach der Methode 02  #
 * # zu rechnen.                                                        #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Kontonummern, die an der 1. Stelle von links der 10- stelligen     #
 * # Kontonummer den Wert 8 oder 9 beinhalten, sind nach der Methode    #
 * # 00 zu rechnen.                                                     #
 * ######################################################################
 */

      case 112:

            /* Variante 1: Methode 02 */
         if(*kto<'8'){
#if DEBUG>0
      case 1112:
         if(retvals){
            retvals->methode="B2a";
            retvals->pz_methode=1112;
         }
#endif
            pz = (kto[0]-'0') * 2
               + (kto[1]-'0') * 9
               + (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_352;   /* pz%=11 */
            if(pz)pz=11-pz;
            INVALID_PZ10;
            CHECK_PZ10;
         }
         else{
#if DEBUG>0
      case 2112:
         if(retvals){
            retvals->methode="B2b";
            retvals->pz_methode=2112;
         }
#endif
               /* Variante 2: Methode 00 */
#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }

/*  Berechnung nach der Methode B3 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B3                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig, ggf. #
 * # ist die Kontonummer für die Prüfzifferberechnung durch             #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * #                                                                    #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7                            #
 * #                                                                    #
 * # Die Kontonummer ist 10-stellig. Kontonummern, die an der 1. Stelle #
 * # von links der 10-stelligen Kontonummer den Wert bis 8 beinhalten   #
 * # sind nach der Methode 32 zu rechen.                                #
 * #                                                                    #
 * #                                                                    #
 * # Variante 2:                                                        #
 * #                                                                    #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #
 * #                                                                    #
 * # Kontonummern, die an der 1. Stelle von links der 10- stelligen     #
 * # Kontonummer den Wert 9 beinhalten sind nach der Methode 06 zu      #
 * # rechen.                                                            #
 * ######################################################################
 */

      case 113:

            /* Variante 1: Methode 32 */
         if(*kto<'9'){
#if DEBUG>0
      case 1113:
         if(retvals){
            retvals->methode="B3a";
            retvals->pz_methode=1113;
         }
#endif
            pz = (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else{

            /* Variante 2: Methode 06 */
#if DEBUG>0
      case 2113:
         if(retvals){
            retvals->methode="B3b";
            retvals->pz_methode=2113;
         }
#endif
            pz = (kto[0]-'0') * 4
               + (kto[1]-'0') * 3
               + (kto[2]-'0') * 2
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

/*  Berechnung nach der Methode B4 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B4                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * #                                                                    #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Kontonummern, die an der 1. Stelle von links der 10-stelligen      #
 * # Kontonummer den Wert 9 beinhalten, sind nach der Methode 00 zu     #
 * # rechnen.                                                           #
 * #                                                                    #
 * # Variante 2:                                                        #
 * #                                                                    #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10                  #
 * # Kontonummern, die an der 1. Stelle von links der 10-stelligen      #
 * # Kontonummer den Wert 0 bis 8 beinhalten, sind nach der Methode     #
 * # 02 zu rechnen.                                                     #
 * ######################################################################
 */

      case 114:

         if(*kto=='9'){
            /* Variante 1: Methode 00 */
#if DEBUG>0
      case 1114:
         if(retvals){
            retvals->methode="B4a";
            retvals->pz_methode=1114;
         }
#endif

#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }
         else{

            /* Variante 2: Methode 02 */
#if DEBUG>0
      case 2114:
         if(retvals){
            retvals->methode="B4b";
            retvals->pz_methode=2114;
         }
#endif
            pz = (kto[0]-'0') * 10
               + (kto[1]-'0') * 9
               + (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_352;   /* pz%=11 */
            if(pz)pz=11-pz;
            INVALID_PZ10;
            CHECK_PZ10;
         }

/*  Berechnung nach der Methode B5 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B5                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 7, 3, 1 ,7, 3, 1, 7, 3, 1                   #
 * # Die Gewichtung entspricht der Methode 05. Die Berechnung           #
 * # entspricht der Methode 01. Führt die Berechnung nach der Variante  #
 * # 1 zu einem Prüfzifferfehler, so sind Kontonummern, die an der 1.   #
 * # Stelle von links der 10-stelligen Kontonummer den Wert 8 oder 9    #
 * # beinhalten, falsch. Alle anderen Kontonummern sind nach der        #
 * # Variante 2 zu prüfen.                                              #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Gewichtung und Berechnung erfolgen nach der Methode  00.           #
 * ######################################################################
 */

      case 115:
#if DEBUG>0
      case 1115:
         if(retvals){
            retvals->methode="B5a";
            retvals->pz_methode=1115;
         }
#endif
         pz = (kto[0]-'0')
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 7
            + (kto[3]-'0')
            + (kto[4]-'0') * 3
            + (kto[5]-'0') * 7
            + (kto[6]-'0')
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 7;

         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;
         if(*kto>'7')return FALSE;

#if DEBUG>0
      case 2115:
         if(retvals){
            retvals->methode="B5b";
            retvals->pz_methode=2115;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;


/*  Berechnung nach der Methode B6 +§§§4 */
/*
 * ######################################################################
 * #          Berechnung nach der Methode B6 (geändert zum 5.9.11)      #
 * ######################################################################
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2,3,4,5,6,7,8,9,3                           #
 * # Kontonummern, die an der 1. Stelle der 10-stelligen Kontonummer    #
 * # den Wert 1-9 oder an den Stellen 1-5 die Werte 02691-02699         #
 * # beinhalten, sind nach der Methode 20 zu prüfen. Alle anderen       #                                               #
 * # Kontonummern sind nach der Variante 2 zu prüfen.                   #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2,4,8,5,10,9,7,3,6,1,2,4                    #
 * # Die Berechnung erfolgt nach der Methode 53.                        #
 * ######################################################################
 */

      case 116:

         if(kto[0]>'0' || (kto[1]=='2' && kto[2]=='6' && kto[3]=='9' && kto[4]>'0')){
#if DEBUG>0
      case 1116:
         if(retvals){
            retvals->methode="B6a";
            retvals->pz_methode=1116;
         }
#endif
            pz = (kto[0]-'0') * 3
               + (kto[1]-'0') * 9
               + (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_352;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else{
#if DEBUG>0
      case 2116:
         if(retvals){
            retvals->methode="B6b";
            retvals->pz_methode=2116;
         }
#endif
            if(!x_blz){
               ok=OK_TEST_BLZ_USED;
               x_blz=(char*)"80053762";
            }
            else
               ok=OK;

               /* Generieren der Konto-Nr. des ESER-Altsystems */
            for(ptr=kto;*ptr=='0';ptr++);
            if(*kto!='0' || *(kto+1)=='0'){  /* Kto-Nr. muß neunstellig sein */
#if DEBUG>0
#endif
               return INVALID_KTO;
            }
            kto_alt[0]=x_blz[4];
            kto_alt[1]=x_blz[5];
            kto_alt[2]=kto[2];         /* T-Ziffer */
            kto_alt[3]=x_blz[7];
            kto_alt[4]=kto[1];
            kto_alt[5]=kto[3];
            for(ptr=kto+4;*ptr=='0' && *ptr;ptr++);
            for(dptr=kto_alt+6;(*dptr= *ptr++);dptr++);
            p1=kto_alt[5];   /* Prüfziffer merken */
            kto_alt[5]='0';
            for(pz=0,ptr=kto_alt+strlen(kto_alt)-1,i=0;ptr>=kto_alt;ptr--,i++)
               pz+=(*ptr-'0')*w52[i];
            kto_alt[5]=p1;   /* Prüfziffer zurückschreiben */
            pz=pz%11;
            p1=w52[i-6];

               /* passenden Faktor suchen */
            tmp=pz;
            for(i=0;i<10;i++){
               pz=tmp+p1*i;
               MOD_11_88;
               if(pz==10)break;
            }
            pz=i; /* Prüfziffer ist der verwendete Faktor des Gewichtes */
#if DEBUG>0
            if(retvals)retvals->pz=pz; 
#endif
            INVALID_PZ10;
            if(*(kto_alt+5)-'0'==pz)
               return ok;
            else
               return FALSE;
         }

/*  Berechnung nach der Methode B7 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B7                        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggff. ist die Kontonummer für die Prüfzifferberechnung durch       #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen. Die    #
 * # 10. Stelle der Kontonummer ist die Prüfziffer.                     #
 * #                                                                    #
 * # Variante 1: Modulus 10, Gewichtung 3, 7, 1, 3, 7, 1, 3, 7, 1       #
 * # Kontonummern der Kontenkreise 0001000000 bis 0005999999 sowie      #
 * # 0700000000 bis 0899999999 sind nach der Methode (Kennziffer) 01    #
 * # zu prüfen. Führt die Berechnung nach der Variante 1 zu einem       #
 * # Prüfzifferfehler, so ist die Kontonummer falsch.                   #
 * #                                                                    #
 * # Variante 2: Für alle anderen Kontonummern gilt die Methode 09      #
 * # (keine Prüfzifferberechnung).                                      #
 * ######################################################################
 */

      case 117:
#if DEBUG>0
      case 1117:
         if(retvals){
            retvals->methode="B7a";
            retvals->pz_methode=1117;
         }
#endif
         if(kto[0]=='0' && ((kto[1]=='7' || kto[1]=='8')
                 || (kto[1]=='0' && kto[2]=='0' && kto[3]>='1' && kto[3]<'6'))){
            pz = (kto[0]-'0')
               + (kto[1]-'0') * 7
               + (kto[2]-'0') * 3
               + (kto[3]-'0')
               + (kto[4]-'0') * 7
               + (kto[5]-'0') * 3
               + (kto[6]-'0')
               + (kto[7]-'0') * 7
               + (kto[8]-'0') * 3;

            MOD_10_160;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }
         else{
#if DEBUG>0
      case 2117:
         if(retvals){
            retvals->methode="B7b";
            retvals->pz_methode=2117;
         }
#endif
            return OK_NO_CHK;
         }

/*  Berechnung nach der Methode B8 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B8 (geändert zum 6.6.11)  #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen. Die    #
 * # 10. Stelle der Kontonummer ist die Prüfziffer.                     #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 3 (modifiziert)     #
 * #                                                                    #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode 20. #
 * # Führt die Berechnung nach Variante 1 zu einem Prüfzifferfehler,    #
 * # so ist nach Variante 2 zu prüfen.                                  #
 * #                                                                    #
 * # Variante 2: Modulus 10, iterierte Transformation.                  #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode 29. #
 * # Führt die Berechnung nach Variante 2 zu einem  Prüfzifferfehler,   #
 * # so ist nach Variante 3 zu prüfen.                                  #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Für die folgenden Kontonummernkreise gilt die Methode 09 (keine    #
 * # Prüfzifferberechnung):                                             #
 * # 10-stellige Kontonummer; 1. + 2. Stelle = 51 - 59                  #
 * # Kontonummernkreis 5100000000 - 5999999999                          #
 * # 10-stellige Kontonummer; Stellen 1 - 3 = 901 - 910                 #
 * # Kontonummernkreis 9010000000 - 9109999999                          #
 * ######################################################################
 */

      case 118:
#if DEBUG>0
      case 1118:
         if(retvals){
            retvals->methode="B8a";
            retvals->pz_methode=1118;
         }
#endif
         pz = (kto[0]-'0') * 3
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

#if DEBUG>0
      case 2118:
         if(retvals){
            retvals->methode="B8b";
            retvals->pz_methode=2118;
         }
#endif
         pz = m10h_digits[0][(unsigned int)(kto[0]-'0')]
            + m10h_digits[3][(unsigned int)(kto[1]-'0')]
            + m10h_digits[2][(unsigned int)(kto[2]-'0')]
            + m10h_digits[1][(unsigned int)(kto[3]-'0')]
            + m10h_digits[0][(unsigned int)(kto[4]-'0')]
            + m10h_digits[3][(unsigned int)(kto[5]-'0')]
            + m10h_digits[2][(unsigned int)(kto[6]-'0')]
            + m10h_digits[1][(unsigned int)(kto[7]-'0')]
            + m10h_digits[0][(unsigned int)(kto[8]-'0')];
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

#if DEBUG>0
      case 3118:
         if(retvals){
            retvals->methode="B8c";
            retvals->pz_methode=3118;
         }
#endif
            /* Variante 3 (neu zum 6.6.2011) */
         if((*kto=='5' && *(kto+1)>'0')
               || (*kto=='9' && *(kto+1)=='0' && *(kto+2)>='1')
               || (*kto=='9' && *(kto+1)=='1' && *(kto+2)=='0'))
            return OK_NO_CHK;
         return FALSE;

/*  Berechnung nach der Methode B9 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode B9                        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Kontonummern mit weniger als zwei oder mehr als drei führenden     #
 * # Nullen sind falsch. Die Kontonummern mit zwei führenden Nullen     #
 * # sind nach Variante 1, mit drei führenden Nullen nach Variante 2    #
 * # zu prüfen.                                                         #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus (11,10), Gewichtung 1, 3, 2, 1, 3, 2, 1                    #
 * # Die für die Berechnung relevanten Stellen der Kontonummer befinden #
 * # sich - von links nach rechts gelesen ­ in den Stellen 3-9 (die     #
 * # Prüfziffer ist in Stelle 10). Sie sind von rechts nach links       #
 * # mit den zugehörigen Gewichtungsfaktoren zu multiplizieren.         #
 * #                                                                    #
 * # Zum jeweiligen Produkt ist der zugehörige Gewichtungsfaktor zu     #
 * # addieren. Das jeweilige Ergebnis ist durch 11 zu dividieren. Die   #
 * # sich aus der Division ergebenden Reste sind zu summieren. Diese    #
 * # Summe ist durch 10 zu dividieren. Der Rest ist die berechnete      #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Führt die Berechnung zu einem Prüfzifferfehler, so ist die         #
 * # berechnete Prüfziffer um 5 zu erhöhen und erneut zu prüfen. Ist    #
 * # die Prüfziffer größer oder gleich 10, ist 10 abzuziehen und das    #
 * # Ergebnis ist dann die Prüfziffer.                                  #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 1, 2, 3, 4, 5, 6                            #
 * # Die für die Berechnung relevanten Stellen der Kontonummer          #
 * # befinden sich - von links nach rechts gelesen - in den Stellen     #
 * # 4-9 (die Prüfziffer ist in Stelle 10). Sie sind von rechts nach    #
 * # links mit den zugehörigen Gewichtungsfaktoren zu multiplizieren.   #
 * # Die Summe dieser Produkte ist zu bilden, und das erzielte          #
 * # Ergebnis ist durch 11 zu dividieren. Der Rest ist die berechnete   #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Führt die Berechnung zu einem Prüfzifferfehler, so ist die         #
 * # berechnete Prüfziffer um 5 zu erhöhen und erneut zu prüfen. Ist    #
 * # die Prüfziffer größer oder gleich 10, ist 10 abzuziehen und das    #
 * # Ergebnis ist dann die Prüfziffer.                                  #
 * ######################################################################
 */

      case 119:
#if DEBUG>0
         if(retvals){
            retvals->methode="B9";
            retvals->pz_methode=119;
         }
#endif
         if(*kto!='0' || kto[1]!='0')return INVALID_KTO;
         if(*kto=='0' && kto[1]=='0' && kto[2]=='0' && kto[3]=='0')return INVALID_KTO;
         if(kto[2]!='0'){
#if DEBUG>0
      case 1119:
         if(retvals){
            retvals->methode="B9a";
            retvals->pz_methode=1119;
         }
#endif
            pz  = (kto[2]-'0') * 1 + 1;   /* Maximum von pz1 ist 9*1+1=10 -> kann direkt genommen werden */

            pz1 = (kto[3]-'0') * 2 + 2;   /* Maximum von pz1 ist 9*2+2=20 -> nur ein Test auf >=11 */
            if(pz1>=11)
               pz+=pz1-11;
            else
               pz+=pz1;

            pz1 = (kto[4]-'0') * 3 + 3;   /* Maximum von pz1 ist 9*3+3=30 -> zwei Tests auf >=22 und >=11 nötig */
            if(pz1>=22)
               pz+=pz1-22;
            else if(pz1>=11)
               pz+=pz1-11;
            else
               pz+=pz1;

            pz += (kto[5]-'0') * 1 + 1;   /* Maximum von pz1 ist 9*1+1=10 -> kann direkt genommen werden */

            pz1 = (kto[6]-'0') * 2 + 2;   /* Maximum von pz1 ist 9*2+2=20 -> nur ein Test auf >=11 */
            if(pz1>=11)
               pz+=pz1-11;
            else
               pz+=pz1;

            pz1 = (kto[7]-'0') * 3 + 3;   /* Maximum von pz1 ist 9*3+3=30 -> zwei Tests auf >=22 und >=11 nötig */
            if(pz1>=22)
               pz+=pz1-22;
            else if(pz1>=11)
               pz+=pz1-11;
            else
               pz+=pz1;

            pz += (kto[8]-'0') * 1 + 1;   /* Maximum von pz1 ist 9*1+1=10 -> kann direkt genommen werden */

            MOD_10_80;   /* pz%=10 */
#if DEBUG>0
            if(retvals)retvals->pz=pz;
#endif
            if(kto[9]-'0'==pz)return OK;
            pz+=5;
            MOD_10_10;
            CHECK_PZ10;
         }
         else{
#if DEBUG>0
      case 2119:
         if(retvals){
            retvals->methode="B9b";
            retvals->pz_methode=2119;
         }
#endif
            pz = (kto[3]-'0') * 6
               + (kto[4]-'0') * 5
               + (kto[5]-'0') * 4
               + (kto[6]-'0') * 3
               + (kto[7]-'0') * 2
               + (kto[8]-'0') * 1;

            MOD_11_176;   /* pz%=11 */

#if DEBUG>0
            if(retvals)retvals->pz=pz;
#endif
            if(kto[9]-'0'==pz)return OK;
            pz+=5;
            MOD_10_10;
            CHECK_PZ10;
         }



/* Berechnungsmethoden C0 bis C9 +§§§3
   Berechnung nach der Methode C0 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C0                        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Kontonummern mit zwei führenden Nullen sind nach Variante 1 zu     #
 * # prüfen. Führt die Berechnung nach der Variante 1 zu einem          #
 * # Prüfzifferfehler, ist die Berechnung nach Variante 2               #
 * # vorzunehmen.                                                       #
 * #                                                                    #
 * # Kontonummern mit weniger oder mehr als zwei führenden Nullen       #
 * # sind ausschließlich nach der Variante 2 zu                         #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 4, 8, 5, 10, 9, 7, 3, 6, 1, 2, 4         #
 * # Die Berechnung und mögliche Ergebnisse entsprechen                 #
 * # der Methode 52.                                                    #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 3                   #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode 20  #
 * ######################################################################
 */
      case 120:
         if(*kto=='0' && kto[1]=='0' && kto[2]!='0'){
#if DEBUG>0
      case 1120:
         if(retvals){
            retvals->methode="C0a";
            retvals->pz_methode=1120;
         }
#endif
            if(!x_blz){
               ok=OK_TEST_BLZ_USED;
               x_blz=(char*)"13051172";
            }
            else
               ok=OK;

               /* Generieren der Konto-Nr. des ESER-Altsystems */
            for(ptr=kto;*ptr=='0';ptr++);
            if(ptr>kto+2)return INVALID_KTO;
            kto_alt[0]=x_blz[4];
            kto_alt[1]=x_blz[5];
            kto_alt[2]=x_blz[6];
            kto_alt[3]=x_blz[7];
            kto_alt[4]= *ptr++;
            kto_alt[5]= *ptr++;
            while(*ptr=='0' && *ptr)ptr++;
            for(dptr=kto_alt+6;(*dptr= *ptr++);dptr++);
            p1=kto_alt[5];   /* Prüfziffer */
            kto_alt[5]='0';
            for(pz=0,ptr=dptr-1,i=0;ptr>=kto_alt;ptr--,i++)
               pz+=(*ptr-'0')*w52[i];
            kto_alt[5]=p1;
            pz=pz%11;
            p1=w52[i-6];

               /* passenden Faktor suchen */
            tmp=pz;
            for(i=0;i<10;i++){
               pz=tmp+p1*i;
               MOD_11_88;
               if(pz==10)break;
            }
            pz=i;
            INVALID_PZ10;
            if(*(kto_alt+5)-'0'==pz)return ok;
#if DEBUG>0
            if(untermethode)return FALSE;
#endif
         }
#if DEBUG>0
      case 2120:
         if(retvals){
            retvals->methode="C0b";
            retvals->pz_methode=2120;
         }
#endif
         pz = (kto[0]-'0') * 3
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

/* Berechnung nach der Methode C1 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C1                        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Kontonummern, die an der 1. Stelle der 10-stelligen                #
 * # Kontonummer einen Wert ungleich  5  beinhalten, sind nach der      #
 * # Variante 1 zu prüfen. Kontonummern, die an der 1. Stelle der       #
 * # 10-stelligen Kontonummer den Wert  5  beinhalten, sind nach        #
 * # der Variante 2 zu prüfen.                                          #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 1, 2, 1, 2, 1, 2                            #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 17. Führt die Berechnung nach der Variante 1 zu einem      #
 * # Prüfzifferfehler, so ist die Kontonummer falsch.                   #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 1, 2, 1, 2, 1, 2                            #
 * # Die Kontonummer ist 10-stellig mit folgendem Aufbau:               #
 * #                                                                    #
 * # KNNNNNNNNP                                                         #
 * # K = Kontoartziffer                                                 #
 * # N = laufende Nummer                                                #
 * # P = Prüfziffer                                                     #
 * #                                                                    #
 * # Für die Berechnung fließen die Stellen 1 bis 9 ein. Stelle 10      #
 * # ist die ermittelte Prüfziffer. Die Stellen 1 bis 9 sind von        #
 * # links nach rechts mit den Ziffern 1, 2, 1, 2, 1, 2, 1, 2, 1        #
 * # zu multiplizieren. Die jeweiligen Produkte sind zu addieren,       #
 * # nachdem aus eventuell zweistelligen Produkten der 2., 4., 6.       #
 * # und 8. Stelle die Quersumme gebildet wurde. Von der Summe ist      #
 * # der Wert  1  zu subtrahieren. Das Ergebnis ist dann durch 11       #
 * # zu dividieren. Der verbleibende Rest wird von 10 subtrahiert.      #
 * # Das Ergebnis ist die Prüfziffer. Verbleibt nach der Division       #
 * # durch 11 kein Rest, ist die Prüfziffer 0.                          #
 * #                                                                    #
 * # Beispiel:                                                          #
 * #                                                                    #
 * # Stellen-Nr.: K   N   N   N   N   N   N   N   N   P                 #
 * # Konto-Nr.:   5   4   3   2   1   1   2   3   4   9                 #
 * # Gewichtung:  1   2   1   2   1   2   1   2   1                     #
 * #              5 + 8 + 3 + 4 + 1 + 2 + 2 + 6 + 4 = 35                #
 * # 35 - 1 = 34                                                        #
 * # 34 : 11 = 3, Rest 1                                                #
 * # 10 - 1 = 9 (Prüfziffer)                                            #
 * ######################################################################
 */

      case 121:
         if(*kto!='5'){ /* Prüfung nach Methode 17 */
#if DEBUG>0
      case 1121:
         if(retvals){
            retvals->methode="C1a";
            retvals->pz_methode=1121;
         }
#endif
#ifdef __ALPHA
            pz =  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else
            pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif

            pz-=1;
            MOD_11_44;   /* pz%=11 */
            if(pz)pz=10-pz;
            CHECK_PZ8;
         }
         else{
#if DEBUG>0
      case 2121:
         if(retvals){
            retvals->methode="C1b";
            retvals->pz_methode=2121;
         }
#endif
#ifdef __ALPHA
            pz =  (kto[0]-'0')
               + ((kto[1]<'5') ? (kto[1]-'0')*2 : (kto[1]-'0')*2-9)
               +  (kto[2]-'0')
               + ((kto[3]<'5') ? (kto[3]-'0')*2 : (kto[3]-'0')*2-9)
               +  (kto[4]-'0')
               + ((kto[5]<'5') ? (kto[5]-'0')*2 : (kto[5]-'0')*2-9)
               +  (kto[6]-'0')
               + ((kto[7]<'5') ? (kto[7]-'0')*2 : (kto[7]-'0')*2-9)
               +  (kto[8]-'0');
#else
            pz =(kto[0]-'0')+(kto[2]-'0')+(kto[4]-'0')+(kto[6]-'0')+(kto[8]-'0');
            if(kto[1]<'5')pz+=(kto[1]-'0')*2; else pz+=(kto[1]-'0')*2-9;
            if(kto[3]<'5')pz+=(kto[3]-'0')*2; else pz+=(kto[3]-'0')*2-9;
            if(kto[5]<'5')pz+=(kto[5]-'0')*2; else pz+=(kto[5]-'0')*2-9;
            if(kto[7]<'5')pz+=(kto[7]-'0')*2; else pz+=(kto[7]-'0')*2-9;
#endif

            pz-=1;
            MOD_11_44;   /* pz%=11 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }


/* Berechnung nach der Methode C2 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C2                        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * # Die 10. Stelle der Kontonummer ist die Prüfziffer.                 #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 3, 1, 3, 1, 3, 1, 3, 1, 3                   #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 22. Führt die Berechnung nach Variante 1 zu einem          #
 * # Prüfzifferfehler, so ist nach Variante 2 zu prüfen.                #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 00.                                                        #
 * ######################################################################
 */

      case 122:
#if DEBUG>0
      case 1122:
         if(retvals){
            retvals->methode="C2a";
            retvals->pz_methode=1122;
         }
#endif
         pz = (kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');

            if(kto[0]<'4')
               pz+=(kto[0]-'0')*3;
            else if(kto[0]<'7')
               pz+=(kto[0]-'0')*3-10;
            else
               pz+=(kto[0]-'0')*3-20;

            if(kto[2]<'4')
               pz+=(kto[2]-'0')*3;
            else if(kto[2]<'7')
               pz+=(kto[2]-'0')*3-10;
            else
               pz+=(kto[2]-'0')*3-20;

            if(kto[4]<'4')
               pz+=(kto[4]-'0')*3;
            else if(kto[4]<'7')
               pz+=(kto[4]-'0')*3-10;
            else
               pz+=(kto[4]-'0')*3-20;

            if(kto[6]<'4')
               pz+=(kto[6]-'0')*3;
            else if(kto[6]<'7')
               pz+=(kto[6]-'0')*3-10;
            else
               pz+=(kto[6]-'0')*3-20;

            if(kto[8]<'4')
               pz+=(kto[8]-'0')*3;
            else if(kto[8]<'7')

               pz+=(kto[8]-'0')*3-10;
            else
               pz+=(kto[8]-'0')*3-20;

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

#if DEBUG>0
      case 2122:
         if(retvals){
            retvals->methode="C2b";
            retvals->pz_methode=2122;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;


/* Berechnung nach der Methode C3 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C3                        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * # Die 10. Stelle der Kontonummer ist die Prüfziffer. Kontonummern,   #
 * # die an der 1. Stelle der 10-stelligen Kontonummer einen Wert       #
 * # ungleich 9 beinhalten, sind nach der Variante 1 zu prüfen.         #
 * # Kontonummern, die an der 1. Stelle der 10-stelligen Kontonummer    #
 * # den Wert 9 beinhalten, sind nach der Variante 2 zu prüfen.         #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 00.                                                        #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 0, 0, 0, 0                   #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 58.                                                        #
 * ######################################################################
 */

      case 123:
         if(kto[0]!='9'){
#if DEBUG>0
      case 1123:
         if(retvals){
            retvals->methode="C3a";
            retvals->pz_methode=1123;
         }
#endif
#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }
         else{
#if DEBUG>0
      case 2123:
         if(retvals){
            retvals->methode="C3b";
            retvals->pz_methode=2123;
         }
#endif
            pz = (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz)pz=11-pz;
            INVALID_PZ10;
            CHECK_PZ10;
         }

/* Berechnung nach der Methode C4 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C4                        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen. Die    #
 * # 10. Stelle der Kontonummer ist die Prüfziffer.                     #
 * # Kontonummern, die an der 1. Stelle der 10-stelligen Kontonummer    #
 * # einen Wert ungleich 9 beinhalten, sind nach der Variante 1 zu      #
 * # prüfen.                                                            #
 * # Kontonummern, die an der 1. Stelle der 10-stelligen Kontonummer    #
 * # den Wert 9 beinhalten, sind nach der Variante 2 zu prüfen.         #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5                                  #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode 15. #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 0, 0, 0, 0                   #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode 58. #
 * ######################################################################
 */

      case 124:
         if(kto[0]!='9'){
#if DEBUG>0
      case 1124:
         if(retvals){
            retvals->methode="C4a";
            retvals->pz_methode=1124;
         }
#endif
            pz = (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_88;    /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else{
#if DEBUG>0
      case 2124:
         if(retvals){
            retvals->methode="C4b";
            retvals->pz_methode=2124;
         }
#endif
            pz = (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz)pz=11-pz;
            INVALID_PZ10;
            CHECK_PZ10;
         }

/* Berechnung nach der Methode C5 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C5                        #
 * ######################################################################
 * #                                                                    #
 * # Die Kontonummern sind einschließlich der Prüfziffer 6- oder 8-     #
 * # bis 10-stellig, ggf. ist die Kontonummer für die Prüfziffer-       #
 * # berechnung durch linksbündige Auffüllung mit Nullen 10-stellig     #
 * # darzustellen.                                                      #
 * #                                                                    #
 * # Die Berechnung der Prüfziffer und die möglichen Ergebnisse         #
 * # richten sich nach dem jeweils bei der entsprechenden Variante      #
 * # angegebenen Kontonummernkreis. Entspricht eine Kontonummer         #
 * # keinem der vorgegebenen Kontonummernkreise oder führt die          #
 * # Berechnung der Prüfziffer nach der vorgegebenen Variante zu        #
 * # einem Prüfzifferfehler, so ist die Kontonummer ungültig.           #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2                               #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 75.                                                        #
 * #                                                                    #
 * # 6-stellige Kontonummern; 5. Stelle = 1-8                           #
 * # Kontonummernkreis 0000100000 bis 0000899999                        #
 * #                                                                    #
 * # 9-stellige Kontonummern; 2. Stelle = 1-8                           #
 * # Kontonummernkreis 0100000000 bis 0899999999                        #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, iterierte Transformation                               #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 29.                                                        #
 * #                                                                    #
 * # 10-stellige Kontonummern, 1. Stelle = 1, 4, 5, 6 oder 9            #
 * # Kontonummernkreis 1000000000 bis 1999999999                        #
 * # Kontonummernkreis 4000000000 bis 6999999999                        #
 * # Kontonummernkreis 9000000000 bis 9999999999                        #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 00.                                                        #
 * # 10-stellige Kontonummern, 1. Stelle = 3                            #
 * # Kontonummernkreis 3000000000 bis 3999999999                        #
 * #                                                                    #
 * # Variante 4:                                                        #
 * # Für die folgenden Kontonummernkreise gilt die Methode 09           #
 * # (keine Prüfzifferberechnung).                                      #
 * #                                                                    #
 * # 8-stellige Kontonummern; 3. Stelle = 3, 4 oder 5                   #
 * # Kontonummernkreis 0030000000 bis 0059999999                        #
 * #                                                                    #
 * # 10-stellige Kontonummern; 1.+ 2. Stelle = 70 oder 85               #
 * # Kontonummernkreis 7000000000 bis 7099999999                        #
 * # Kontonummernkreis 8500000000 bis 8599999999                        #
 * ######################################################################
 */

      case 125:
#if DEBUG>0
      case 1125:
         if(retvals){
            retvals->methode="C5a";
            retvals->pz_methode=1125;
         }
#endif

            /* Variante 1a:
             *  6-stellige Kontonummern; 5. Stelle = 1-8, Prüfziffer an Stelle 10
             */
         if(kto[0]=='0' && kto[1]=='0' && kto[2]=='0' && kto[3]=='0' && kto[4]>='1' && kto[4]<='8'){
#ifdef __ALPHA
            pz = ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz=(kto[5]-'0')+(kto[7]-'0');
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }

            /* Variante 1b:
             *    9-stellige Kontonummern; 2. Stelle = 1-8, Prüfziffer an Stelle 7
             */
         else if(kto[0]=='0' && kto[1]>='1' && kto[1]<='8'){
#ifdef __ALPHA
            pz = ((kto[1]<'5') ? (kto[1]-'0')*2 : (kto[1]-'0')*2-9)
               +  (kto[2]-'0')
               + ((kto[3]<'5') ? (kto[3]-'0')*2 : (kto[3]-'0')*2-9)
               +  (kto[4]-'0')
               + ((kto[5]<'5') ? (kto[5]-'0')*2 : (kto[5]-'0')*2-9);
#else
            pz=(kto[2]-'0')+(kto[4]-'0');
            if(kto[1]<'5')pz+=(kto[1]-'0')*2; else pz+=(kto[1]-'0')*2-9;
            if(kto[3]<'5')pz+=(kto[3]-'0')*2; else pz+=(kto[3]-'0')*2-9;
            if(kto[5]<'5')pz+=(kto[5]-'0')*2; else pz+=(kto[5]-'0')*2-9;
#endif
         MOD_10_40;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ7;
         }

            /* Variante 2: 10-stellige Kontonummern, 1. Stelle = 1, 4, 5, 6 oder 9 */
         else if(kto[0]=='1' || (kto[0]>='4' && kto[0]<='6') || kto[0]=='9'){
#if DEBUG>0
      case 2125:
         if(retvals){
            retvals->methode="C5b";
            retvals->pz_methode=2125;
         }
#endif
            pz = m10h_digits[0][(unsigned int)(kto[0]-'0')]
               + m10h_digits[3][(unsigned int)(kto[1]-'0')]
               + m10h_digits[2][(unsigned int)(kto[2]-'0')]
               + m10h_digits[1][(unsigned int)(kto[3]-'0')]
               + m10h_digits[0][(unsigned int)(kto[4]-'0')]
               + m10h_digits[3][(unsigned int)(kto[5]-'0')]
               + m10h_digits[2][(unsigned int)(kto[6]-'0')]
               + m10h_digits[1][(unsigned int)(kto[7]-'0')]
               + m10h_digits[0][(unsigned int)(kto[8]-'0')];
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }

            /* Variante 3: 10-stellige Kontonummern, 1. Stelle = 3 */
         else if(kto[0]=='3'){
#if DEBUG>0
      case 3125:
         if(retvals){
            retvals->methode="C5c";
            retvals->pz_methode=3125;
         }
#endif
#ifdef __ALPHA
            pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
               +  (kto[1]-'0')
               + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +  (kto[3]-'0')
               + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +  (kto[5]-'0')
               + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
               +  (kto[7]-'0')
               + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }

            /* Variante 4:
             *    8-stellige KOntonummern mit 3. Stelle = 3,4, oder 5
             *    10-stellige Kontonummern, 1. und 2. Stelle = 70 oder 85:
             */
         else if( (kto[0]=='0' && kto[1]=='0' && kto[2]>='3' && kto[2]<='5')
               || (kto[0]=='7' && kto[1]=='0')
               || (kto[0]=='8' && kto[1]=='5')){
#if DEBUG>0
      case 4125:
         if(retvals){
            retvals->methode="C5d";
            retvals->pz_methode=4125;
         }
#endif
         return OK_NO_CHK;
      }
      else  /* Kontonummer entspricht keinem vorgegebenen Kontenkreis */
         return INVALID_KTO;

/* Berechnung nach der Methode C6 +§§§4 */
/*
 * ######################################################################
 * #   Berechnung nach der Methode C6  (letze Änderung 4.3.2013)        #
 * ######################################################################
 * # Modulus 10, Gewichtung 1, 2, 1, 2, 1, 2, 1, 2                      #
 * #                                                                    #
 * # Die Kontonummer ist 10-stellig, ggf. ist die Kontonummer für die   #
 * # Prüfzifferberechnung durch linksbündige Auffüllung mit Nullen      #
 * # 10-stellig darzustellen. Die 10. Stelle der Konto-nummer ist die   #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Alle Kontonummern sind wie folgt zu prüfen:                        #
 * #                                                                    #
 * # Für die Berechnung der Prüfziffer werden die Stellen 2 bis 9 der   #
 * # Kontonummer verwendet. Diese Stellen sind links um eine Zahl       #
 * # (Konstante) gemäß der folgenden Tabelle zu ergänzen.               #
 * #                                                                    #
 * #   1. Stelle von links                                              #
 * #     der 10-stelligen                                               #
 * #       Kontonummer    Zahl (Konstante)                              #
 * #                                                                    #
 * #            0          4451970                                      #
 * #            1          4451981                                      #
 * #            2          4451992                                      #
 * #            3          4451993                                      #
 * #            4          4344992                                      #
 * #            5          4344990                                      #
 * #            6          4344991                                      #
 * #            7          5499570                                      #
 * #            8          4451994                                      #
 * #            9          5499579                                      #
 * #                                                                    #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode 00. #
 * ######################################################################
 * # Anmerkung zur Berechnung (MP): Da die Konstante immer nur einen    #
 * # festen Wert zur Berechnung beiträgt, wird diese Berechnung nicht   #
 * # gemacht, sondern gleich der Wert als Initialwert für die Quersumme #
 * # verwendet. Die Berechnung beginnt erst mit der zweiten Stelle der  #
 * # Kontonummer.                                                       #
 * ######################################################################
 */

      case 126:
#if DEBUG>0
         if(retvals){
            retvals->methode="C6";
            retvals->pz_methode=126;
         }
#endif
         switch(kto[0]){
            case '0': pz=30; break;
            case '1': pz=33; break;
            case '2': pz=36; break;
            case '3': pz=38; break; /* neu zum 7.6.2010 */
            case '4': pz=45; break; /* neu zum 4.3.2013 */
            case '5': pz=41; break; /* neu zum 6.6.2011 */
            case '6': pz=43; break; /* neu zum 6.6.2011 */
            case '7': pz=31; break;
            case '8': pz=40; break; /* neu zum 4.3.2013 */
            case '9': pz=40; break;
            default: return INVALID_KTO;
         }

#ifdef __ALPHA
         pz += (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz+=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_160;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnung nach der Methode C7 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C7                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1                                                         #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1                            #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 63. Führt die Berechnung nach Variante 1 zu einem          #
 * # Prüfzifferfehler, so ist nach Variante 2 zu prüfen.                #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7 (modifiziert)              #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode 06  #
 * ######################################################################
 */

      case 127:
         if(*kto=='0'){ /* bei Methode 63 sind 10-stellige Kontonummern falsch */
            if(*(kto+1)=='0' && *(kto+2)=='0'){
               /* evl. Unterkonto weggelassen; das kommt wohl eher vor als
                * 7-stellige Nummern (Hinweis T.F.); stimmt auch mit
                * http://www.kontonummern.de/check.php überein.
               */
#if DEBUG>0
      case 3127:
         if(retvals){
            retvals->methode="C7c";
            retvals->pz_methode=3127;
         }
#endif
               if(*kto!='0')return INVALID_KTO;
#ifdef __ALPHA
               pz =   (kto[3]-'0')
                  +  ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
                  +   (kto[5]-'0')
                  +  ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
                  +   (kto[7]-'0')
                  +  ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
               pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
               if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
               if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
               if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
               MOD_10_80;   /* pz%=10 */
               if(pz)pz=10-pz;
               CHECK_PZX10;
            }
               /* hier darf kein else-Zweig hin, damit nach 63c auch 63a geprüft wird */
#if DEBUG>0
      case 1127:
         if(retvals){
            retvals->methode="C7a";
            retvals->pz_methode=1127;
         }
#endif
               if(*kto!='0')return INVALID_KTO;
#ifdef __ALPHA
               pz =   (kto[1]-'0')
               +  ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
               +   (kto[3]-'0')
               +  ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
               +   (kto[5]-'0')
               +  ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9);
#else
            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
#endif
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZX8;
         }

      /* Variante 2 */
#if DEBUG>0
      case 2127:
         if(retvals){
            retvals->methode="C7b";
            retvals->pz_methode=2127;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;


/* Berechnung nach der Methode C8 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C8                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #  
 * # Gewichtung und Berechnung erfolgen nach der Methode 00. Führt      # 
 * # die Berechnung nach Variante 1 zu einem Prüfzifferfehler, so ist   #    
 * # nach Variante 2 zu prüfen.                                         #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #  
 * # Gewichtung und Berechnung erfolgen nach der Methode 04. Führt      # 
 * # auch die Berechnung nach Variante 2 zu einem Prüfzifferfehler,     #  
 * # oder ist keine gültige Prüfziffer zu ermitteln, d.h. Rest 1 nach   #
 * # der Division durch 11, so ist nach Variante 3 zu prüfen.           #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10                  #   
 * # Gewichtung und Berechnung erfolgen nach der Methode 07.            #  
 * ######################################################################
 */

      case 128:
      /* Variante 1 */
#if DEBUG>0
      case 1128:
         if(retvals){
            retvals->methode="C8a";
            retvals->pz_methode=1128;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

      /* Variante 2 */
#if DEBUG>0
      case 2128:
         if(retvals){
            retvals->methode="C8b";
            retvals->pz_methode=2128;
         }
#endif
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz)pz=11-pz;
         CHECK_PZX10;

      /* Variante 3 */
#if DEBUG>0
      case 3128:
         if(retvals){
            retvals->methode="C8c";
            retvals->pz_methode=3128;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz)pz=11-pz;
         INVALID_PZ10;
         CHECK_PZ10;

/* Berechnung nach der Methode C9 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode C9                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Gewichtung und Berechnung erfolgen nach der Methode 00. Führt die  #
 * # Berechnung nach Variante 1 zu einem Prüfzifferfehler, so ist nach  #
 * # Variante 2 zu prüfen.                                              #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10                  #
 * # Gewichtung und Berechnung erfolgen nach der Methode 07.            #
 * ######################################################################
 */

      case 129:
      /* Variante 1 */
#if DEBUG>0
      case 1129:
         if(retvals){
            retvals->methode="C9a";
            retvals->pz_methode=1129;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

      /* Variante 2 */
#if DEBUG>0
      case 2129:
         if(retvals){
            retvals->methode="C9b";
            retvals->pz_methode=2129;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz)pz=11-pz;
         INVALID_PZ10;
         CHECK_PZ10;

/* Berechnungsmethoden D0 bis D9 +§§§3
 * Berechnung nach der Methode D0 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode D0                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * # Kontonummern, die an der 1. und 2. Stelle der 10-stelligen         #
 * # Kontonummer einen Wert ungleich ,,57" beinhalten, sind nach der    #
 * # Variante 1 zu prüfen. Kontonummern, die an der 1. und 2. Stelle    #
 * # der 10-stelligen Kontonummer den Wert "57" beinhalten, sind nach   #
 * # der Variante 2 zu prüfen.                                          #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 3 (modifiziert)     #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode     #
 * # 20. Führt die Berechnung nach der Variante 1 zu einem              #
 * # Prüfzifferfehler, so ist die Kontonummer falsch.                   #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Für den Kontonummernkreis 5700000000 bis 5799999999 gilt die       #
 * # Methode 09 (keine Prüfzifferberechnung, alle Kontonummern sind     #
 * # als richtig zu werten).                                            #
 * ######################################################################
 */

      case 130:

      /* Variante 2 */
#if DEBUG>0
      case 2130:
         if(retvals){
            retvals->methode="D0b";
            retvals->pz_methode=2130;
         }
#endif
         if(kto[0]=='5' && kto[1]=='7')
            return OK_NO_CHK;
         else{

      /* Variante 1 */
#if DEBUG>0
      case 1130:
         if(retvals){
            retvals->methode="D0a";
            retvals->pz_methode=1130;
         }
#endif
            pz = (kto[0]-'0') * 3
               + (kto[1]-'0') * 9
               + (kto[2]-'0') * 8
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_352;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

/*  Berechnung nach der Methode D1 +§§§4 */
/*
 * ######################################################################
 * #   Berechnung nach der Methode D1 (letzte Änderung 4.3.2013)        #
 * ######################################################################
 * # Modulus 10, Gewichtung 1, 2, 1, 2, 1, 2, 1, 2                      #
 * #                                                                    #
 * # Die Kontonummer ist 10-stellig, ggf. ist die Kontonummer für die   #
 * # Prüfzifferberechnung durch linksbündige Auffüllung mit Nullen      #
 * # 10-stellig darzustellen. Die 10. Stelle der Kontonummer ist die    #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Kontonummern, die an der 1. Stelle von links der 10-stelligen      #
 * # Kontonummer den Wert 8 enthalten sind falsch.                      #
 * #                                                                    #
 * # Kontonummern, die an der 1. Stelle von links der 10-stelligen      #
 * # Kontonummer einen der Werte 0, 1, 2, 3, 4, 5, 6, 7 oder 9          #
 * # beinhalten sind wie folgt zu prüfen:                               #
 * #                                                                    #
 * # Für die Berechnung der Prüfziffer werden die Stellen 2 bis 9 der   #
 * # Kontonummer von links verwendet. Diese Stellen sind links um eine  #
 * # Zahl (Konstante) gemäß der folgenden Tabelle zu ergänzen.          #
 * # zu ergänzen.                                                       #
 * #                                                                    #
 * #       1. Stelle von links   Zahl (Konstante)                       #
 * #        der 10-stelligen                                            #
 * #        Kontonummer                                                 #
 * #                 0                  4363380                         #                                                                                                   #
 * #                 1                  4363381                         #                                                                                           #
 * #                 2                  4363382                         #                                                                                           #
 * #                 3                  4363383                         #
 * #                 4                  4363384                         #
 * #                 5                  4363385                         #
 * #                 6                  4363386                         #
 * #                 7                  4363387                         #
 * #                 9                  4363389                         #
 * #                                                                    #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der             #
 * # Methode 00.                                                        #
 * ######################################################################
 * # Anmerkung zur Berechnung (MP): die zusätzliche feste Konstante     #
 * # wird wie in Methode C6 im voraus berechnet und als Initialwert für #
 * # die Quersumme verwendet. Die Berechnung beginnt allerdings -       #
 * # entgegen der Beschreibung - mit der ersten Stelle der Kontonummer, #
 * # da diese in der Konstanten enthalten ist.                          #
 * ######################################################################
 */

      case 131:
#if DEBUG>0
         if(retvals){
            retvals->methode="D1";
            retvals->pz_methode=131;
         }
#endif
         if(*kto=='8')return INVALID_KTO;
         pz=31;

#ifdef __ALPHA
         pz+= ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz+=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode D2 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode D2                        #
 * ######################################################################
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 2, 3, 4                   #
 * # Die Berechnung, Ausnahmen und möglichen Ergebnisse entsprechen     #
 * # der Methode 95. Führt die Berechnung nach Variante 1 zu einem      #
 * # Prüfzifferfehler, so ist nach Variante 2 zu prüfen.                #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Berechnung und möglichen Ergebnisse entsprechen der Methode    #
 * # 00. Führt auch die Berechnung nach Variante 2 zu einem Prüfziffer- #
 * # fehler, so ist nach Variante 3 zu prüfen.                          #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Berechnung, Ausnahmen und möglichen Ergebnisse entsprechen     #
 * # der Methode 68. Führt auch die Berechnung nach Variante 3 zu       #
 * # einem Prüfzifferfehler, so ist die Kontonummer falsch.             #
 * ######################################################################
 */
      case 132:
#if DEBUG>0
         if(retvals){
            retvals->methode="D2";
            retvals->pz_methode=132;
         }
#endif

      /* Variante 1 */
#if DEBUG>0
      case 1132:
         if(retvals){
            retvals->methode="D2a";
            retvals->pz_methode=1132;
         }
#endif
         if(   /* Ausnahmen: keine Prüfzifferberechnung */
            (strcmp(kto,"0000000001")>=0 && strcmp(kto,"0001999999")<=0)
         || (strcmp(kto,"0009000000")>=0 && strcmp(kto,"0025999999")<=0)
         || (strcmp(kto,"0396000000")>=0 && strcmp(kto,"0499999999")<=0)
         || (strcmp(kto,"0700000000")>=0 && strcmp(kto,"0799999999")<=0))
            return OK_NO_CHK;
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Variante 2: Methode 00 */
#if DEBUG>0
      case 2132:
         if(retvals){
            retvals->methode="D2b";
            retvals->pz_methode=2132;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

            /* Variante 3: Methode 68, mit diversen Sonderfällen. Sie werden 
             * hier allerdings nicht getrennt nummeriert, sondern alle unter
             * Variante 3 geführt.
             */

#if DEBUG>0
      case 3132:
         if(retvals){
            retvals->methode="D2c";
            retvals->pz_methode=3132;
         }
#endif
            /* Sonderfall: keine Prüfziffer */
         if(*kto=='0' && *(kto+1)=='4'){
#if DEBUG>0
            pz= *(kto+9)-'0';
#endif
            return OK_NO_CHK;
         }

            /* 10stellige Kontonummern */
         if(*kto!='0'){
            if(*(kto+3)!='9')return INVALID_KTO;
#ifdef __ALPHA
         pz = 9           /* 7. Stelle von rechts */
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=9+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_40;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;
         }

            /* 6 bis 9stellige Kontonummern: Variante 1 */
#ifdef __ALPHA
         pz =  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
#if DEBUG>0
         if(retvals)retvals->pz=pz;
#endif
         if(*(kto+9)-'0'==pz)return OK;

            /* 6 bis 9stellige Kontonummern: Variante 2 */
#ifdef __ALPHA
         pz =  (kto[1]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else

         pz=(kto[1]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_40;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*  Berechnung nach der Methode D3 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode D3                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Gewichtung und Berechnung erfolgen nach der Methode 00. Führt die  #
 * # Berechnung nach Variante 1 zu einem Prüfzifferfehler, so ist nach  #
 * # Variante 2 zu prüfen.                                              #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2 (modifiziert)     #
 * # Gewichtung und Berechnung erfolgen nach der Methode 27.            #
 * ######################################################################
 */

      case 133:
#if DEBUG>0
         if(retvals){
            retvals->methode="D3";
            retvals->pz_methode=133;
         }
#endif

      /* Variante 1 */
#if DEBUG>0
      case 1133:
         if(retvals){
            retvals->methode="D3a";
            retvals->pz_methode=1133;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

      /* Variante 2 */
#if DEBUG>0
      case 2133:
         if(retvals){
            retvals->methode="D3b";
            retvals->pz_methode=2133;
         }
#endif

            /* Kontonummern von 1 bis 999.999.999:
             * In Methode 27 wird dieser Kontenkreis nach der Methode 00 geprüft;
             * da diese Prüfung jedoch schon (mit einem Fehler) erfolgte, kann
             * man an dieser Stelle für maximal 9-stellige Kontonummern einfach
             * FALSE zurückgeben.
             */
         if(*kto=='0')return FALSE;
         pz = m10h_digits[0][(unsigned int)(kto[0]-'0')]
            + m10h_digits[3][(unsigned int)(kto[1]-'0')]
            + m10h_digits[2][(unsigned int)(kto[2]-'0')]
            + m10h_digits[1][(unsigned int)(kto[3]-'0')]
            + m10h_digits[0][(unsigned int)(kto[4]-'0')]
            + m10h_digits[3][(unsigned int)(kto[5]-'0')]
            + m10h_digits[2][(unsigned int)(kto[6]-'0')]
            + m10h_digits[1][(unsigned int)(kto[7]-'0')]
            + m10h_digits[0][(unsigned int)(kto[8]-'0')];
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnung nach der Methode D4 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode D4 (geändert zum 6.6.11)  #
 * ######################################################################
 * # Modulus 10, Gewichtung 1, 2, 1, 2, 1, 2, 1, 2                      #
 * #                                                                    #
 * # Die Kontonummer ist 10-stellig, ggf. ist die Kontonummer für die   #
 * # Prüfzifferberechnung durch linksbündige Auffüllung mit Nullen      #
 * # 10-stellig darzustellen. Die 10. Stelle der Kontonummer ist die    #
 * # Prüfziffer.                                                        #
 * #                                                                    #
 * # Kontonummern, die an der 1. Stelle von links der 10-stelligen      #
 * # Kontonummer den Wert 0 beinhalten, sind falsch.                    #
 * #                                                                    #
 * # Kontonummern, die an der 1. Stelle von links der 10- stelligen     #
 * # Kontonummer einen der Werte 1, 2, 3, 4, 5, 6, 7, 8 oder 9          #
 * # beinhalten, sind wie folgt zu prüfen:                              #
 * #                                                                    #
 * # Für die Berechnung der Prüfziffer werden die Stellen 1 bis 9 der   #
 * # Kontonummer von links verwendet. Diese Stellen sind links um die   #
 * # Zahl (Konstante) "428259" zu ergänzen.                             #
 * #                                                                    #
 * # Die Berechnung und mögliche Ergebnisse entsprechen der Methode 00. #
 * ######################################################################
 */

      case 134:
#if DEBUG>0
         if(retvals){
            retvals->methode="D4";
            retvals->pz_methode=134;
         }
#endif
         if(*kto=='0')
            return INVALID_KTO;
         else
            pz=29;

   /* die Berechnung entspricht komplett der Methode D1 und wurde auch von da
    * kopiert - der einzige Unterschied sind die ungültigen Kontonummern.
    */

#ifdef __ALPHA
         pz+= ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz+=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnung nach der Methode D5 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode D5                        #
 * ######################################################################
 * #                                                                    #
 * #  1. Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 0, 0               #
 * #  2. Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0               #
 * #  3. Modulus 7, Gewichtung  2, 3, 4, 5, 6, 7, 0, 0, 0               #
 * #  4. Modulus 10, Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0               #
 * #                                                                    #
 * #  Die Kontonummer ist einschließlich der Prüfziffer (P) 10-stellig, #
 * #  ggf. ist die Kontonummer für die Prüfziffer-berechnung durch      #
 * #  linksbündige Auffüllung mit Nullen 10-stellig darzustellen.       #
 * #                                                                    #
 * #  Konten mit der Ziffernfolge 99 an Stelle 3 und 4 (xx99xxxxxx)     #
 * #  sind nur nach Variante 1 zu prüfen. Alle übrigen Konten sind      #
 * #  nacheinander nach den Varianten 2, ggf. 3 und ggf. 4 zu prüfen.   #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 0, 0                   #
 * #                                                                    #
 * # In die Prüfzifferberechnung werden nur die Stellen 3 bis 9         #
 * # einbezogen. Die Stelle 10 ist die Prüfziffer (P). Die weitere      #
 * # Berechnung erfolgt nach dem Verfahren 06.                          #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0                   #
 * #                                                                    #
 * # In die Prüfzifferberechnung werden nur die Stellen 4 bis 9         #
 * # einbezogen. Die Stelle 10 ist die Prüfziffer (P). Die weitere      #
 * # Berechnung erfolgt nach dem Verfahren 06.                          #
 * #                                                                    #
 * # Führt die Berechnung zu einem Fehler, ist nach Variante 3 zu       #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Modulus 7, Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0                    #
 * #                                                                    #
 * # Die Stellen 4 bis 9 der Kontonummer werden von rechts nach links   #
 * # mit den Gewichten multipliziert. Die jeweiligen Produkte werden    #
 * # addiert. Die Summe ist durch 7 zu dividieren. Der verbleibende     #
 * # Rest wird vom Divisor (7) subtrahiert. Das Ergebnis ist die        #
 * # Prüfziffer (Stelle 10). Verbleibt nach der Division durch 7 kein   #
 * # Rest, ist die Prüfziffer 0.                                        #
 * #                                                                    #
 * # Führt die Berechnung zu einem Fehler, ist nach Variante 4 zu       #
 * # prüfen.                                                            #
 * #                                                                    #
 * # Variante 4:                                                        #
 * # Modulus 10, Gewichtung 2, 3, 4, 5, 6, 7, 0, 0, 0                   #
 * #                                                                    #
 * # Die Berechnung erfolgt analog zu Variante 3, jedoch ist als        #
 * # Divisor der Wert 10 zu verwenden.Verbleibt nach der Division       #
 * # durch 10 kein Rest, ist die Prüfziffer 0.                          #
 * ######################################################################
 */

      case 135:
#if DEBUG>0
         if(retvals){
            retvals->methode="D5";
            retvals->pz_methode=135;
         }
#endif
         if(kto[2]=='9' && kto[3]=='9'){
#if DEBUG>0
      case 1135:
         if(retvals){
            retvals->methode="D5a";
            retvals->pz_methode=1135;
         }
#endif
            pz = 3   /* die Stellen 3 und 4 sind 99; das ergibt einen Rest von 3 */
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }

#if DEBUG>0
      case 2135:
         if(retvals){
            retvals->methode="D5b";
            retvals->pz_methode=2135;
         }
#endif
            pz = (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZX10;

#if DEBUG>0
      case 3135:
         if(retvals){
            retvals->methode="D5c";
            retvals->pz_methode=3135;
         }
#endif
            pz = (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_7_224;   /* pz%=7 */
            if(pz)pz=7-pz;
            CHECK_PZX10;

#if DEBUG>0
      case 4135:
         if(retvals){
            retvals->methode="D5d";
            retvals->pz_methode=4135;
         }
#endif
            pz = (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_10_160;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZ10;

/* Berechnung nach der Methode D6 +§§§4 */
/*
 * ######################################################################
 * #              Berechnung nach der Methode D6                        #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Die Berechnung entspricht der Methode 07. Führt die Berechnung     #
 * # nach Variante 1 zu einem Prüfzifferfehler, so ist nach Variante    #
 * # 2 zu prüfen.                                                       #
 * #                                                                    #
 * # Variante 2                                                         #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Berechnung entspricht der Methode 03.                          #
 * # Führt die Berechnung nach Variante 2 zu einem Prüfzifferfehler,    #
 * # so ist nach Variante 3 zu prüfen.                                  #
 * #                                                                    #
 * #                                                                    #
 * # Variante 3                                                         #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Berechnung entspricht der Methode 00.                          #
 * # Führt auch die Berechnung nach Variante 3 zu einem                 #
 * # Prüfzifferfehler, so ist die Kontonummer falsch.                   #
 * ######################################################################
 */

      case 136:
#if DEBUG>0
         if(retvals){
            retvals->methode="D6";
            retvals->pz_methode=136;
         }
#endif

   /* Variante 1: Berechnung nach Methode 07 */
#if DEBUG>0
      case 1136:
         if(retvals){
            retvals->methode="D6a";
            retvals->pz_methode=1136;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz)pz=11-pz;
         CHECK_PZX10;

   /* Variante 2: Berechnung nach Methode 03 */
#if DEBUG>0
      case 2136:
         if(retvals){
            retvals->methode="D6b";
            retvals->pz_methode=2136;
         }
#endif
         pz = (kto[0]-'0') * 2
            + (kto[1]-'0')
            + (kto[2]-'0') * 2
            + (kto[3]-'0')
            + (kto[4]-'0') * 2
            + (kto[5]-'0')
            + (kto[6]-'0') * 2
            + (kto[7]-'0')
            + (kto[8]-'0') * 2;

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;

   /* Variante 3: Berechnung nach Methode 00 */
#if DEBUG>0
      case 3136:
         if(retvals){
            retvals->methode="D6c";
            retvals->pz_methode=3136;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/*    Berechnung nach der Methode D7 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode D7                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Die Stellen der Kontonummer sind von rechts nach links mit         #
 * # den Ziffern 2, 1, 2, 1, 2, 1,  2, 1, 2 zu multiplizieren. Die      #
 * # jeweiligen Produkte werden addiert, nachdem jeweils aus den        #
 * # zweistelligen Produkten die Quersumme gebildet wurde (z. B.        #
 * # Produkt 18 = Quersumme 9). Nach der Addition bleiben außer         #
 * # der Einerstelle alle anderen Stellen unberücksichtigt; diese       #
 * # Einerstelle ist die Prüfziffer (Ergebnis = 27 / Prüfziffer = 7).   #
 * ######################################################################
 * # Anm. (M.P.): Die Methode entspricht (bis auf die Subtraktion von   #
 * # 10) der Prüfziffermethode 00, und wird auch weitgehend von dieser  #
 * # Methode kopiert.                                                   #
 * ######################################################################
 */
      case 137:
#if DEBUG>0
         if(retvals){
            retvals->methode="D7";
            retvals->pz_methode=137;
         }
#endif
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
            /* hier kommt beim Prüfzifferverfahren 00 noch eine hochkomplizierte Zusatzrechnung ;-))) */
         CHECK_PZ10;

/*    Berechnung nach der Methode D8 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode D8                       #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * # Die Berechnung der Prüfziffer und die möglichen Ergebnisse         #
 * # richten sich nach dem jeweils bei der entsprechenden  Variante     #
 * # angegebenen Kontonummernkreis. Entspricht eine  Kontonummer        #
 * # keinem der vorgegebenen Kontonummernkreise oder führt die          #
 * # Berechnung der Prüfziffer nach der Variante 1 zu einem             #
 * # Prüfzifferfehler, so ist die Kontonummer ungültig.                 #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Für Kontonummern aus dem Kontonummernkreis                         #
 * # 1000000000 bis 9999999999 entsprechen die Berechnung               #
 * # und mögliche Ergebnisse der Methode 00.                            #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Für den Kontonummernkreis 0010000000 bis 0099999999 gilt  die      #
 * # Methode 09 (keine Prüfzifferberechnung, alle Kontonummern sind     #
 * # als richtig zu werten).                                            #
 * ######################################################################
 */
      case 138:
#if DEBUG>0
         if(retvals){
            retvals->methode="D8";
            retvals->pz_methode=138;
         }
#endif

#if DEBUG>0
      case 2138:
         if(retvals){
            retvals->methode="D8b";
            retvals->pz_methode=2138;
         }
#endif
   if(*kto=='0'){
      if(*(kto+1)=='0' && *(kto+2)>'0')
         return OK_NO_CHK;
      else
         return INVALID_KTO;
   }

#if DEBUG>0
      case 1138:
         if(retvals){
            retvals->methode="D8a";
            retvals->pz_methode=1138;
         }
#endif
   /* Berechnung nach der Methode 00 */
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnung nach der Methode D9 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode D9                       #
 * ######################################################################
 * # Die Kontonummer ist einschließlich der Prüfziffer 10-stellig,      #
 * # ggf. ist die Kontonummer für die Prüfzifferberechnung durch        #
 * # linksbündige Auffüllung mit Nullen 10-stellig darzustellen.        #
 * #                                                                    #
 * # Variante 1:                                                        #
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * #                                                                    #
 * # Gewichtung und Berechnung erfolgen nach der Methode 00. Führt      #
 * # die Berechnung nach Variante 1 zu einem Prüfzifferfehler, so       #
 * # ist nach Variante 2 zu prüfen.                                     #
 * #                                                                    #
 * # Variante 2:                                                        #
 * # Modulus 11, Gewichtung 2, 3, 4, 5, 6, 7, 8, 9, 10                  #
 * #                                                                    #
 * # Gewichtung und Berechnung erfolgen nach der Methode 10.            #
 * # Führt die Berechnung nach Variante 2 zu einem Prüfzifferfehler,    #
 * # so ist nach Variante 3 zu prüfen.                                  #
 * #                                                                    #
 * # Variante 3:                                                        #
 * # Modulus 10, Gewichtung 3, 9, 7, 1, 3, 9, 7, 1, 3                   #
 * #                                                                    #
 * # Gewichtung und Berechnung erfolgen nach der Methode 18.            #
 * ######################################################################
 */

      case 139:
#if DEBUG>0
         if(retvals){
            retvals->methode="D9";
            retvals->pz_methode=139;
         }
#endif
#if DEBUG>0
      case 1139:
         if(retvals){
            retvals->methode="D9a";
            retvals->pz_methode=1139;
         }
#endif
   /* Berechnung nach der Methode 00 */
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX10;


            /* Variante 2: Berechnung nach Methode 10 */
#if DEBUG>0
      case 2139:
         if(retvals){
            retvals->methode="D9b";
            retvals->pz_methode=2139;
         }
#endif
         pz = (kto[0]-'0') * 10
            + (kto[1]-'0') * 9
            + (kto[2]-'0') * 8
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_352;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX10;

            /* Variante 3: Berechnung nach Methode 18 */
#if DEBUG>0
      case 3139:
         if(retvals){
            retvals->methode="D9c";
            retvals->pz_methode=3139;
         }
#endif
         pz = (kto[0]-'0') * 3
            + (kto[1]-'0')
            + (kto[2]-'0') * 7
            + (kto[3]-'0') * 9
            + (kto[4]-'0') * 3
            + (kto[5]-'0')
            + (kto[6]-'0') * 7
            + (kto[7]-'0') * 9
            + (kto[8]-'0') * 3;

         MOD_10_320;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

/* Berechnungsmethoden E0 bis E9 +§§§3
   Berechnung nach der Methode E0 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode E0                       #
 * ######################################################################
 * # Modulus 10, Gewichtung 2, 1, 2, 1, 2, 1, 2, 1, 2                   #
 * # Die Stellen der Kontonummer sind von rechts nach links mit den     #
 * # Ziffern 2, 1, 2, 1, 2 usw. zu multiplizieren. Die jeweiligen       #
 * # Produkte werden addiert, nachdem jeweils aus den zweistelligen     #
 * # Produkten die Quersumme gebildet wurde (z. B. Produkt 18 =         #
 * # Quersumme 9) plus den Wert 7. Nach der Addition bleiben außer      #
 * # der Einerstelle alle anderen Stellen unberücksichtigt. Die         #
 * # Einerstelle wird von dem Wert 10 subtrahiert. Das Ergebnis ist     #
 * # die Prüfziffer (10. Stelle der Kontonummer). Ergibt sich nach der  #
 * # Subtraktion der Rest 10, ist die Prüfziffer 0.                     #
 * ######################################################################
 */

      case 140:
#if DEBUG>0
         if(retvals){
            retvals->methode="E0";
            retvals->pz_methode=140;
         }
#endif

            /* Das Verfahren entspricht (bis auf die zusätzliche 7) genau dem
             * Verfahren 00; der Programmcode ist auch von diesem kopiert.
             */
#ifdef __ALPHA
         pz = ((kto[0]<'5') ? (kto[0]-'0')*2 : (kto[0]-'0')*2-9)
            +  (kto[1]-'0')
            + ((kto[2]<'5') ? (kto[2]-'0')*2 : (kto[2]-'0')*2-9)
            +  (kto[3]-'0')
            + ((kto[4]<'5') ? (kto[4]-'0')*2 : (kto[4]-'0')*2-9)
            +  (kto[5]-'0')
            + ((kto[6]<'5') ? (kto[6]-'0')*2 : (kto[6]-'0')*2-9)
            +  (kto[7]-'0')
            + ((kto[8]<'5') ? (kto[8]-'0')*2 : (kto[8]-'0')*2-9);
#else
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[0]<'5')pz+=(kto[0]-'0')*2; else pz+=(kto[0]-'0')*2-9;
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
#endif
         pz+=7;
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;


/* Berechnung nach der Methode E1 +§§§4 */
/*
 * ######################################################################
 * #               Berechnung nach der Methode E1                       #
 * ######################################################################
 * #                                                                    #
 * # Modulus 11, Gewichtung 1, 2, 3, 4, 5, 6, 11, 10, 9                 #
 * # Die Kontonummer sowohl für Kontokorrentkonten als auch für         #
 * # Sparkonten ist 9-stellig und für die Prüfzifferberechnung durch    #
 * # linksbündige Auffüllung mit einer Null 10-stellig darzustellen.    #
 * # Die 10. Stelle der Kontonummer ist die Prüfziffer.                 #
 * # Vor der Berechnung der Prüfziffer sind die einzelnen Stellen der   #
 * # Kontonummer durch folgende Werte (ASCII Wert) zu ersetzen:         #
 * #                                                                    #
 * # Ziffern der Kontonummer      0  1  2  3  4  5  6  7  8  9          #
 * # ASCII-Wert                  48 49 50 51 52 53 54 55 56 57          #
 * #                                                                    #
 * # Die einzelnen ASCII-Werte sind von rechts nach links mit den       #
 * # Ziffern 1, 2, 3, 4, 5, 6, 11, 10, 9 zu multiplizieren. Die         #
 * # jeweiligen Produkte werden addiert. Die Summe ist durch 11 zu      #
 * # dividieren. Der verbleibende Rest ist die Prüfziffer. Verbleibt    #
 * # nach der Division durch 11 kein Rest, ist die Prüfziffer 0.        #
 * # Ergibt sich ein Rest 10, ist die Kontonummer falsch.               #
 * #                                                                    #
 * # Anmerkung (M.P.): nach der Multiplikation wird ein Wert von 2442   #
 * # subtrahiert; dies ist ein Vielfaches von 11, das sich bei der      #
 * # "Kontonummer" 00000000 ergibt. Durch die ASCII-Darstellung wird    #
 * # das Ergebnis nur unnötig vergrößert; die Subtraktion ändert das    #
 * # Endergebnis nicht, bringt aber die Summe in einen Bereich, der für #
 * # das Makros MOD_11_352 akzeptabel ist.                              #
 * ######################################################################
 */

      case 141:
#if DEBUG>0
         if(retvals){
            retvals->methode="E1";
            retvals->pz_methode=141;
         }
#endif
            /* Die Form (kto[x]-'0'+48) ist für ASCII-basierte Plattformen nur
             * die Addition einer 0 (sie dürfte vom Compiler wegoptimiert
             * werden), für nicht-ASCII Plattformen jedoch notwendig.
             */
         pz = (kto[0]-'0'+48) *  9
            + (kto[1]-'0'+48) * 10
            + (kto[2]-'0'+48) * 11
            + (kto[3]-'0'+48) *  6
            + (kto[4]-'0'+48) *  5
            + (kto[5]-'0'+48) *  4
            + (kto[6]-'0'+48) *  3
            + (kto[7]-'0'+48) *  2
            + (kto[8]-'0'+48)
            - 2442;

         MOD_11_352;   /* pz%=11 */
         if(pz==10)return FALSE;
         CHECK_PZ10;


/* nicht abgedeckte Fälle +§§§3 */
/*
 * ######################################################################
 * #               nicht abgedeckte Fälle                               #
 * ######################################################################
 */
      default:
#if DEBUG>0
         if(retvals){
            retvals->methode="(-)";
            retvals->pz_methode=-1;
         }
         if(untermethode)return UNDEFINED_SUBMETHOD; 
#endif
         return NOT_IMPLEMENTED;
   }
}

/*
 * ######################################################################
 * #               Ende der Berechnungsmethoden                         #
 * ######################################################################
 */

/* Funktion kto_check_blz() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_blz() ist die neue externe Schnittstelle zur     #
 * # Überprüfung einer BLZ/Kontonummer Kombination. Es wird grundsätzlich    #
 * # nur mit Bankleitzahlen gearbeitet; falls eine Prüfziffermethode direkt  #
 * # aufgerufen werden soll, ist stattdessen die Funktion kto_check_pz()     #
 * # zu benutzen.                                                            #
 * #                                                                         #
 * # Bei dem neuen Interface sind außerdem Initialisierung und Test          #
 * # getrennt. Vor einem Test ist (einmal) die Funktion kto_check_init()     #
 * # aufzurufen; diese Funktion liest die LUT-Datei und initialisiert einige #
 * # interne Variablen. Wenn diese Funktion nicht aufgerufen wurde, wird die #
 * # Fehlermeldung LUT2_NOT_INITIALIZED zurückgegeben.                       #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    blz:        Bankleitzahl (immer 8-stellig)                           #
 * #    kto:        Kontonummer                                              #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_blz(char *blz,char *kto)
{
   char *ptr;
   int idx,pz_methode;

      /* alle notwendigen Parameter da? */
   if(!blz || !kto)return MISSING_PARAMETER;

   /* Flags für init_status:
    *    -  1 Variablen sind initialisiert
    *    -  2 BLZ-Array wurde geladen
    *    -  4 Prüfziffermethoden wurden geladen
    *    -  8 (Neu-)Initialisierung gestartet
    *    - 16 Aufräumen/Speicherfreigabe gestartet
    */
   if(init_status!=7){
      if(init_status&24)INITIALIZE_WAIT;
      if(init_status<7)return LUT2_NOT_INITIALIZED;
   }
   if((idx=lut_index(blz))<0){ /* falsche BLZ o.a. */
      if(((*(ptr=blz)==0x73&&*++ptr==0x75&&*++ptr==0x6d&&*++ptr==0x6d)||
            (*(ptr=blz)==0x31&&*++ptr==0x33&&*++ptr==0x31&&*++ptr==0x37
             &&*++ptr==0x31&&*++ptr==0x33&&*++ptr==0x31&&*++ptr==0x37))&&*ee)return EE;
      return idx;
   }
   pz_methode=pz_methoden[idx];
   if(aenderung && aenderung[startidx[idx]]=='D')return BLZ_MARKED_AS_DELETED;
#if DEBUG>0
   return kto_check_int(blz,pz_methode,kto,0,NULL);
#else
   return kto_check_int(blz,pz_methode,kto);
#endif
}

/* Funktion kto_check_regel() und kto_check_regel_dbg +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_regel() entspricht der Funktion                  #
 * # kto_check_blz(). Der einzige Unterschied ist, daß vor dem Test geprüft  #
 * # wird, ob für die  BLZ/Konto-Kombination eine IBAN-Regel angewendet      #
 * # werden muß (z.B. bei Spendenkonten etc.). U.U. wird die BLZ und/oder    #
 * # Kontonummer ersetzt  und die Berechnung mit den modifizierten Werten    #
 * # gemacht.                                                                #
 * #                                                                         #
 * # Die Funktion kto_check_regel_dbg() ist das Gegenstück zu                #
 * # kto_check_blz_dbg(); bei dieser Funktion werden zusätzlich noch einige  #
 * # interne Werte zurückgegeben. Die beiden Variablen blz2 und kto2         #
 * # müssen auf einen Speicherbereich von mindestens 9 bzw. 11 Byte zeigen;  #
 * # in diese Speicherbereiche werden die neue BLZ bzw. Kontonummer          #
 * # geschrieben. Es bietet sich an, für diese Aufgabe lokale Variablen der  #
 * # aufrufenden Funktion zu wählen.                                         #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    blz:        Bankleitzahl (immer 8-stellig)                           #
 * #    kto:        Kontonummer                                              #
 * #    blz2:       benutzte BLZ (evl. durch die Regeln modifiziert)         #
 * #    kto2:       benutzte Kontonummer (evl. modifiziert)                  #
 * #    bic:        BIC der benutzten Bank                                   #
 * #    Regel:      benutzte IBAN-Regel                                      #
 * #    retvals:    Struktur, in der die benutzte Prüfziffermethode und die  #
 * #                berechnete Prüfziffer zurückgegeben werden               #
 * #                                                                         #
 * # Copyright (C) 2013 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

#if DEBUG>0    /* es werden einige Funktionen benutzt, die nur in der Debug-Variante enthalten sind */
DLL_EXPORT int kto_check_regel_dbg(char *blz,char *kto,char *blz2,char *kto2,const char **bic,int *regel,RETVAL *retvals)
{
#if USE_IBAN_RULES
   char *blz_o,buffer[32],kto_o[16],*blz_n,*kto_n,*ptr,*dptr;
   const char *bicp;
   int ret,ret_regel,r;

   if(regel)*regel=0;
   if(blz2 && kto2){
      blz_n=blz2;
      kto_n=kto2;
   }
   else{
      blz_n=buffer;
      kto_n=buffer+10;
   }
   memcpy(blz_n,blz,9);
   for(ptr=kto;*ptr;ptr++);   /* Ende von kto suchen */
   ptr--;
   memcpy(kto_n,"0000000000",10);
   kto_n[10]=0;
   for(dptr=kto_n+9;ptr>=kto;)*dptr--=*ptr--;

       /* alte Versionen von kto und BLZ für Vergleich merken */
   memcpy(kto_o,kto_n,11);
   blz_o=blz;
   kto=kto_n;
   blz=blz_n;
   r=lut_iban_regel(blz,0,&ret);
   if(regel && ret>0)*regel=r;
   if(retvals){
         /* in retvals noch Werte für den Fehlerfall eintragen */
      retvals->pz=-1;
      retvals->methode="-";
      retvals->pz_methode=-1;
      retvals->pz_pos=-1;
   }
   ret_regel=iban_regel_cvt(blz,kto,&bicp,r,retvals);
   if(!bicp)bicp=lut_bic(blz,0,NULL);
   if(bic)*bic=bicp;
   if(ret_regel<OK)return ret_regel;
   ret=kto_check_blz_dbg(blz,kto,retvals);
   if(strcmp(blz,blz_o) || strcmp(kto,kto_o)){  /* BLZ und/oder Kto ersetzt */
      if(ret_regel>3)   /* ret_regel<1 wurde schon oben zurückgegeben */
         return ret_regel;
      else
         return ret;
   }
   else  /* BLZ und Kto gleich */
      return ret;
#else
   if(regel)*regel=0;
   if(retvals)*retvals=NULL;
   return kto_check_regel(blz,kto);
#endif
}

#else   /* !DEBUG */
DLL_EXPORT int kto_check_regel_dbg(char *blz,char *kto,char *blz2,char *kto2,const char **bic,int *regel,RETVAL *retvals){return DEBUG_ONLY_FUNCTION;}
#endif   /* DEBUG */

DLL_EXPORT int kto_check_regel(char *blz,char *kto)
{
#if USE_IBAN_RULES
   char *blz_o,blz_n[10],kto_o[16],kto_n[16],*ptr,*dptr;
   const char *bicp;
   int ret,ret_regel,regel;

   memcpy(blz_n,blz,9);
   for(ptr=kto;*ptr;ptr++);   /* Ende von kto suchen */
   ptr--;
   memcpy(kto_n,"0000000000",10);
   kto_n[10]=0;
   for(dptr=kto_n+9;ptr>=kto;)*dptr--=*ptr--;

       /* alte Versionen von kto und BLZ für Vergleich merken */
   memcpy(kto_o,kto_n,16);
   blz_o=blz;
   kto=kto_n;
   blz=blz_n;
   regel=lut_iban_regel(blz,0,&ret);
   if((ret_regel=iban_regel_cvt(blz,kto,&bicp,regel,NULL))<OK)return ret_regel;
   ret=kto_check_blz(blz,kto);
   if(strcmp(blz,blz_o) || strcmp(kto,kto_o)){  /* BLZ und/oder Kto ersetzt */
      if(ret_regel>3)   /* ret_regel<1 wurde schon oben zurückgegeben */
         return ret_regel;
      else
         return ret;
   }
   else  /* BLZ und Kto gleich */
      return ret;
#else
   return kto_check_blz(blz,kto);
#endif
}

/* Funktion kto_check_pz() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_pz() ist die neue externe Schnittstelle zur      #
 * # Überprüfung einer Prüfziffer/Kontonummer Kombination. Diese Funktion    #
 * # dient zum Test mit direktem Aufruf einer Prüfziffermethode. Bei dieser  #
 * # Funktion kann der Aufruf von kto_check_init() entfallen. Die BLZ wird   #
 * # bei einigen Methoden, die auf das ESER-Altsystem zurückgehen, benötigt  #
 * # (52, 53, B6, C0); ansonsten wird sie ignoriert.                         #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    pz:         Prüfziffer (2- oder 3-stellig)                           #
 * #    kto:        Kontonummer                                              #
 * #    blz:        Bankleitzahl (immer 8-stellig)                           #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_pz(char *pz,char *kto,char *blz)
{
   int pz_methode;
#if DEBUG>0
   int untermethode;
#endif

      /* zunächst testen, ob noch eine andere Initialisierung läuft (z.B. in einem anderen Thread) */
   INITIALIZE_WAIT;

      /* Umwandlungsarrays initialisieren, falls noch nicht gemacht */
   if(!(init_status&1))init_atoi_table(); /* Werte für init_status: cf. kto_check_blz() */

   pz_methode=bx2[UI *pz]+b1[UI *(pz+1)]+by4[UI *(pz+2)];
   if(*(pz+2) && *(pz+3))return UNDEFINED_SUBMETHOD; /* maximal drei Stellen für den pz-String */
#if DEBUG>0
   untermethode=by1[UI *(pz+2)];
   if(!blz || !*blz || *blz=='0')blz=NULL;  /* BLZs können nicht mit 0 anfangen; evl. 0 übergeben */
   return kto_check_int(blz,pz_methode,kto,untermethode,NULL);
#else
   return kto_check_int(blz,pz_methode,kto);
#endif
}

/* Funktion kto_check_blz_x() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_blz_x() ist eine Hilfsfunktion für die Funktion  #
 * # iban_gen(). Diese Funktion bestimmt, ob für ein angegebenes Konto evl.  #
 * # ein Unterkonto weggelassen wurde (betrifft die Methode 13, 26, 50, 63,  #
 * # 76 und C7; ansonsten entspricht sie der Funktion kto_check_blz().       #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    blz:        Bankleitzahl (immer 8-stellig)                           #
 * #    kto:        Kontonummer                                              #
 * #    uk_cnt:     Rückgabewert: Anzahl weggelassener Unterkontostellen     #
 * #                                                                         #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int kto_check_blz_x(char *blz,char *kto,int *uk_cnt)
{
   char *ptr,*dptr,xkto[32];
   int i,p1=0,kto_len,pz,fuehrende_nullen;
   int idx,pz_methode,untermethode=0;
   RETVAL *retvals=NULL;

   if(!blz || !kto)return MISSING_PARAMETER;
   *uk_cnt=0;
   if(init_status!=7){
      if(init_status&24)INITIALIZE_WAIT;
      if(init_status<7)return LUT2_NOT_INITIALIZED;
   }
   if((idx=lut_index(blz))<0)return idx;
   pz_methode=pz_methoden[idx];

   memset(xkto,'0',12);
   for(ptr=kto;*ptr=='0' || *ptr==' ' || *ptr=='\t';ptr++);
   for(kto_len=0;*ptr && *ptr!=' ' && *ptr!='\t';kto_len++,ptr++);
   dptr=xkto+10;
   *dptr--=0;
   if(kto_len<1 || kto_len>10)return INVALID_KTO_LENGTH;
   for(ptr--,i=kto_len;i-->0;*dptr--= *ptr--);
   kto=xkto;
   for(fuehrende_nullen=i=0;i<3;i++)if(kto[i]=='0')fuehrende_nullen++; else break;

   switch(pz_methode){
      case 13:
            /* Methode 13a */
         pz =(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZX8;
         if(fuehrende_nullen<2)return FALSE;   /* Methode 13b nur möglich, falls 1. und 2. Stelle '0' sind */

            /* Methode 13b: 2-stelliges Unterkonto weggelassen */
         *uk_cnt=2;
         pz =(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;

         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ10;

      case 26:
         if(fuehrende_nullen>=2){
               /* Unterkontonummer ausgelassen */
            *uk_cnt=2;
            pz = (kto[2]-'0') * 2
               + (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else{
            *uk_cnt=-1; /* Unterkonto angegeben */
            pz = (kto[0]-'0') * 2
               + (kto[1]-'0') * 7
               + (kto[2]-'0') * 6
               + (kto[3]-'0') * 5
               + (kto[4]-'0') * 4
               + (kto[5]-'0') * 3
               + (kto[6]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ8;
         }

      case 50:
            /* Methode 50a */
         pz = (kto[0]-'0') * 7
            + (kto[1]-'0') * 6
            + (kto[2]-'0') * 5
            + (kto[3]-'0') * 4
            + (kto[4]-'0') * 3
            + (kto[5]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZX7;

            /* Methode 50b 
             *
             * es ist eine reale Kontonummer bekannt, bei der rechts nur eine
             * Null weggelassen wurde; daher wird die Berechnung für die
             * Methode 50b leicht modifiziert, so daß eine, zwei oder drei
             * Stellen der Unterkontonummer 000 weggelassen werden können.
             */
         if(kto[0]=='0' && kto[1]=='0' && kto[2]=='0'){
            *uk_cnt=3;
            pz = (kto[3]-'0') * 7
               + (kto[4]-'0') * 6
               + (kto[5]-'0') * 5
               + (kto[6]-'0') * 4
               + (kto[7]-'0') * 3
               + (kto[8]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ10;
         }
         else if(kto[0]=='0' && kto[1]=='0' && kto[9]=='0'){
            *uk_cnt=2;
            pz = (kto[2]-'0') * 7
               + (kto[3]-'0') * 6
               + (kto[4]-'0') * 5
               + (kto[5]-'0') * 4
               + (kto[6]-'0') * 3
               + (kto[7]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ9;
         }
         else if(kto[0]=='0' && kto[8]=='0' && kto[9]=='0'){
            *uk_cnt=1;
            pz = (kto[1]-'0') * 7
               + (kto[2]-'0') * 6
               + (kto[3]-'0') * 5
               + (kto[4]-'0') * 4
               + (kto[5]-'0') * 3
               + (kto[6]-'0') * 2;

            MOD_11_176;   /* pz%=11 */
            if(pz<=1)
               pz=0;
            else
               pz=11-pz;
            CHECK_PZ8;
         }
         return FALSE;

      case 63:
         if(*kto!='0')return INVALID_KTO;
         if(*(kto+1)=='0' && *(kto+2)=='0'){ /* wahrscheinlich Unterkonto weggelassen */
            *uk_cnt=2;
            pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZX10;
         }
         pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
         if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
         if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
         if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
         MOD_10_80;   /* pz%=10 */
         if(pz)pz=10-pz;
         CHECK_PZ8;

      case 76:
               /* Methode 76a */
         if((p1= *kto)=='1' || p1=='2' || p1=='3' || p1=='5')return INVALID_KTO;
         pz = (kto[1]-'0') * 7
            + (kto[2]-'0') * 6
            + (kto[3]-'0') * 5
            + (kto[4]-'0') * 4
            + (kto[5]-'0') * 3
            + (kto[6]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         CHECK_PZX8;

               /* Methode 76b */
         if(kto[0]!='0' || kto[1]!='0')return FALSE;
         if((p1=kto[2])=='1' || p1=='2' || p1=='3' || p1=='5')return INVALID_KTO;
         *uk_cnt=2;
         pz = (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz==10)return INVALID_KTO;
         CHECK_PZ10;

      case 127:
         if(*kto=='0'){ /* bei Methode 63 sind 10-stellige Kontonummern falsch */
            if(*(kto+1)=='0' && *(kto+2)=='0'){

               /* Methode C7c */

               /* wahrscheinlich Unterkonto weggelassen; das kommt wohl eher
                * vor als 7-stellige Nummern (Hinweis T.F.); stimmt auch mit
                * http://www.kontonummern.de/check.php überein.
               */
               *uk_cnt=2;
               pz=(kto[3]-'0')+(kto[5]-'0')+(kto[7]-'0');
               if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
               if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
               if(kto[8]<'5')pz+=(kto[8]-'0')*2; else pz+=(kto[8]-'0')*2-9;
               MOD_10_80;   /* pz%=10 */
               if(pz)pz=10-pz;
               CHECK_PZX10;
               *uk_cnt=0; /* Bedingung nicht erfüllt, Unterkto. zurücksetzen */
            }
               /* Methode C7a */
            pz=(kto[1]-'0')+(kto[3]-'0')+(kto[5]-'0');
            if(kto[2]<'5')pz+=(kto[2]-'0')*2; else pz+=(kto[2]-'0')*2-9;
            if(kto[4]<'5')pz+=(kto[4]-'0')*2; else pz+=(kto[4]-'0')*2-9;
            if(kto[6]<'5')pz+=(kto[6]-'0')*2; else pz+=(kto[6]-'0')*2-9;
            MOD_10_80;   /* pz%=10 */
            if(pz)pz=10-pz;
            CHECK_PZX8;
         }

            /* Methode C7b */
            /* Variante 2 */
         pz = (kto[0]-'0') * 4
            + (kto[1]-'0') * 3
            + (kto[2]-'0') * 2
            + (kto[3]-'0') * 7
            + (kto[4]-'0') * 6
            + (kto[5]-'0') * 5
            + (kto[6]-'0') * 4
            + (kto[7]-'0') * 3
            + (kto[8]-'0') * 2;

         MOD_11_176;   /* pz%=11 */
         if(pz<=1)
            pz=0;
         else
            pz=11-pz;
         CHECK_PZ10;

      default:
         *uk_cnt=-2;
#if DEBUG>0
         return kto_check_int(blz,pz_methode,kto,untermethode,NULL);
#else
         return kto_check_int(blz,pz_methode,kto);
#endif
   }
}

/* Funktion kto_check_blz_dbg() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_blz_dbg() ist die Debug-Version von              #
 * # kto_check_blz(); sie hat dieselbe Funktionalität wie diese, kann in dem #
 * # zusätzlichen Parameter jedoch noch einige Werte aus der Prüfroutine     #
 * # zurückgeben. Diese Variante wird in dem neuen Interface anstelle der    #
 * # alten globalen Variablen benutzt.                                       #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    blz:        Bankleitzahl (immer 8-stellig)                           #
 * #    kto:        Kontonummer                                              #
 * #    retvals:    Struktur, in der die benutzte Prüfziffermethode und die  #
 * #                berechnete Prüfziffer zurückgegeben werden               #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

#if DEBUG>0
DLL_EXPORT int kto_check_blz_dbg(char *blz,char *kto,RETVAL *retvals)
{
   char *ptr;
   int idx,pz_methode;

      /* Rückgabeparameter für Fehler initialisieren */
   retvals->pz=-1;
   retvals->methode="(-)";
   retvals->pz_methode=-1;
   retvals->pz_pos=-1;

      /* alle notwendigen Parameter da? */
   if(!blz || !kto)return MISSING_PARAMETER;

      /* zunächst testen, ob noch eine andere Initialisierung läuft (z.B. in einem anderen Thread) */
   INITIALIZE_WAIT;
   if(init_status!=7){
      if(init_status&24)INITIALIZE_WAIT;
      if(init_status<7)return LUT2_NOT_INITIALIZED;
   }
   if((idx=lut_index(blz))<0){ /* falsche BLZ o.a. */
      if(((*(ptr=blz)==0x73&&*++ptr==0x75&&*++ptr==0x6d&&*++ptr==0x6d)||
            (*(ptr=blz)==0x31&&*++ptr==0x33&&*++ptr==0x31&&*++ptr==0x37
             &&*++ptr==0x31&&*++ptr==0x33&&*++ptr==0x31&&*++ptr==0x37))&&*ee)return EE;
      if(*blz++==0x73&&*blz++==0x75&&*blz++==0x6d&&*blz==0x6d&&*ee)return EE;
      return idx;
   }
   pz_methode=pz_methoden[idx];
   return kto_check_int(blz,pz_methode,kto,0,retvals);
}

/* Funktion kto_check_pz_dbg() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_pz_dbg() ist die Debug-Version von               #
 * # kto_check_pz(); sie hat dieselbe Funktionalität wie diese, kann in dem  #
 * # zusätzlichen Parameter jedoch noch einige Werte aus der Prüfroutine     #
 * # zurückgeben. Diese Variante wird in dem neuen Interface anstelle der    #
 * # alten globalen Variablen benutzt. Die BLZ wird bei einigen Methoden,    #
 * # die auf das ESER-Altsystem zurückgehen (52, 53, B6, C0), benötigt;      #
 * # ansonsten wird sie ignoriert.                                           #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    pz:         Prüfziffer                                               #
 * #    kto:        Kontonummer                                              #
 * #    blz:        Bankleitzahl (immer 8-stellig)                           #
 * #    retvals:    Struktur, in der die benutzte Prüfziffermethode und die  #
 * #                berechnete Prüfziffer zurückgegeben werden               #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */
DLL_EXPORT int kto_check_pz_dbg(char *pz,char *kto,char *blz,RETVAL *retvals)
{
   int untermethode,pz_methode;

      /* Rückgabeparameter für Fehler initialisieren */
   retvals->pz=-1;
   retvals->methode="(-)";
   retvals->pz_methode=-1;
   retvals->pz_pos=-1;

      /* alle notwendigen Parameter da? */
   if(!pz || !kto)return MISSING_PARAMETER;

      /* Umwandlungsarrays initialisieren, falls noch nicht gemacht */
   INITIALIZE_WAIT;
   if(!(init_status&1))init_atoi_table();

   pz_methode=bx2[UI *pz]+b1[UI *(pz+1)]+by4[UI *(pz+2)];
   if(*(pz+2))pz_methode+=b0[UI *(pz+3)]; /* bei drei Stellen testen, ob der pz-String länger ist als 3 Stellen */
   untermethode=by1[UI *(pz+2)];
   if(blz && *blz=='0')blz=NULL;  /* BLZs können nicht mit 0 anfangen; evl. 0 übergeben */
   return kto_check_int(blz,pz_methode,kto,untermethode,retvals);
}
#else   /* !DEBUG */
DLL_EXPORT int kto_check_blz_dbg(char *blz,char *kto,RETVAL *retvals){return DEBUG_ONLY_FUNCTION;}
DLL_EXPORT int kto_check_pz_dbg(char *pz,char *kto,char *blz,RETVAL *retvals){return DEBUG_ONLY_FUNCTION;}
#endif   /* !DEBUG */

/* Funktion kto_check_str() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_str() entspricht der Funktion konto_check();     #
 * # die Rückgabe ist allerdings ein String mit einer kurzen Fehlermeldung   #
 * # statt eines numerischen Wertes. Die Funktion wurde zunächst für die     #
 * # Perl-Variante eingeführt.                                               #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *kto_check_str(char *x_blz,char *kto,char *lut_name)
{
   return kto_check_retval2txt_short(kto_check(x_blz,kto,lut_name));
}


/* Anmerkung zur alten threadfesten Version der Routinen +§§§1
 *
 * ###########################################################################
 * # Im Folgenden sind eine Reihe Funktionen mit den Namen *_t enthalten,    #
 * # die einen zusätzlichen Parameter ctx (vom Typ KTO_CHK_CTX) enthalten.   #
 * # Dieser Parameter wird ab Version 3.0 ignoriert; er war in Version 2     #
 * # eingeführt, um die Routinen threadfest zu machen. Durch den Parameter   #
 * # wurden R/W static Variablen, die potentiell von mehreren Instanzen des  #
 * # Programms beschrieben werden können, auf eine lokale Variable umge-     #
 * # setzt. Ab Version 3.0 sind jedoch alle globalen R/W Variablen durch     #
 * # lokale Variablen ersetzt worden, so daß die Funktionen auch ohne diesen #
 * # (schmutzigen) Trick threadfest sind. Der Parameter wird nicht mehr      #
 * # benötigt, die Funktionen sind nur noch aus Kompatibilitätsgründen in    #
 * # der Library enthalten und rufen einfach die entsprechenden Funktionen   #
 * # ohne den ctx-Parameter auf.                                             #
 * ###########################################################################
 */

/* Funktion kto_check() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check() ist die alte externe Schnittstelle zur         #
 * # Überprüfung einer Kontonummer. Diese Funktion ist ab Version 3.0 nur    #
 * # noch als Wrapper zu den neueren Funktionen definiert; im Normalfall     #
 * # sollten diese benutzt werden.                                           #
 * #                                                                         #
 * # Die Variable kto_check_msg wird *nicht* mehr gesetzt; stattdessen       #
 * # sollte die Funktion kto_check_str() oder die kto_check_retval2txt()     #
 * # benutzt werden, um den Rückgabewert als Klartext zu erhalten.           #
 * #                                                                         #
 * # Auch die Variable pz_str wird nicht mehr unterstützt; stattdessen       #
 * # können die neuen Funktionen kto_check_blz_dbg (bei Benutzung mit        #
 * # Bankleitzahl) und kto_check_pz_dbg (Benutzung direkt mit Prüfziffer)    #
 * # verwendet werden, die mittels eines zusätzlichen Parameters eine        #
 * # analoge Funktionalität bieten. Die Variablen kto_check_msg und pz_str   #
 * # werden ab der Version 3.0 einfach fest auf eine entsprechende           #
 * # Fehlermeldung gesetzt.                                                  #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    x_blz:      Prüfziffer (2-stellig) oder BLZ (8-stellig)              #
 * #    kto:        Kontonummer                                              #
 * #    lut_name:   Name der Lookup-Datei oder NULL (für DEFAULT_LUT_NAME)   #
 * #                                                                         #
 * # Copyright (C) 2002-2007 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_t(char *x_blz,char *kto,char *lut_name,KTO_CHK_CTX *ctx)
{
   return kto_check(x_blz,kto,lut_name);
}

DLL_EXPORT int kto_check(char *pz_or_blz,char *kto,char *lut_name)
{
   int idx,retval,pz_methode;
#if DEBUG>0
   int untermethode;
#endif

      /* alle notwendigen Parameter da? */
   if(!pz_or_blz || !kto)return MISSING_PARAMETER;

   INITIALIZE_WAIT;   /* zunächst testen, ob noch eine andere Initialisierung läuft (z.B. in einem anderen Thread) */

   /* Flags für init_status:
    *    -  1 Variablen sind initialisiert
    *    -  2 BLZ-Array wurde geladen
    *    -  4 Prüfziffermethoden wurden geladen
    *    -  8 Initialisierung gestartet
    */

      /* 2 Ziffern: Prüfziffermethode */
   if(!*(pz_or_blz+2)){
         /* Umwandlungsarrays initialisieren, falls noch nicht gemacht */
      if(!(init_status&1))init_atoi_table(); /* Werte für init_status: cf. kto_check_blz() */
      pz_methode=bx2[UI *pz_or_blz]+b1[UI *(pz_or_blz+1)];
#if DEBUG>0
      return kto_check_int(NULL,pz_methode,kto,0,NULL);
#else
      return kto_check_int(NULL,pz_methode,kto);
#endif
   }

      /* drei Ziffern: Prüfziffermethode + Untermethode (in der dritten Stelle) */
   else if(!*(pz_or_blz+3)){
         /* Umwandlungsarrays initialisieren, falls noch nicht gemacht */
      if(!(init_status&1))init_atoi_table();
      pz_methode=bx2[UI *pz_or_blz]+b1[UI *(pz_or_blz+1)]+by4[UI *(pz_or_blz+2)];
#if DEBUG>0
      untermethode=by1[UI *(pz_or_blz+2)];
      return kto_check_int(NULL,pz_methode,kto,untermethode,NULL);
#else
      return kto_check_int(NULL,pz_methode,kto);
#endif
   }

   else{
   if(init_status!=7){ /* Werte für init_status: cf. kto_check_blz() */
      if(init_status&24)INITIALIZE_WAIT;
      if(init_status<7 && (retval=kto_check_init_p(lut_name,1,0,0))<=0
           && retval!=LUT2_PARTIAL_OK && retval!=LUT1_SET_LOADED)RETURN(retval);
      if(init_status<7)  /* irgendwas ist schiefgelaufen, müßte jetzt eigentlich ==7 sein */
         return LUT2_NOT_INITIALIZED;
   }
   if((idx=lut_index(pz_or_blz))<0){ /* falsche BLZ o.a. */
      if(*pz_or_blz++==0x73&&*pz_or_blz++==0x75&&*pz_or_blz++==0x6d&&*pz_or_blz==0x6d&&*ee)return EE;
      return idx;
   }
   if(aenderung && aenderung[startidx[idx]]=='D')return BLZ_MARKED_AS_DELETED;
   pz_methode=pz_methoden[idx];

#if DEBUG>0
   return kto_check_int(pz_or_blz,pz_methode,kto,0,NULL);
#else
   return kto_check_int(pz_or_blz,pz_methode,kto);
#endif
   }
}

/* Funktion bic_check() +§§§1 */
/* ###########################################################################
 * # Die Funktion bic_check() testet ob ein BIC gültig ist. Falls ja, wird   #
 * # die Anzahl der Banken die zu dem BIC gehören, in der Variablen cnt      #
 * # zurückgegeben (optional).                                               #
 * #                                                                         #
 * # Copyright (C) 2013 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int bic_check(char *search_bic,int *cnt)
{
   int retval;

   if(cnt)*cnt=0; /* Anzahl für Fehlerfälle auf 0 */
   if(toupper(search_bic[4])!='D' || toupper(search_bic[5])!='E')return BIC_ONLY_GERMAN;   /* nur deutsche BICs möglich */
   if(strlen(search_bic)!=8 && strlen(search_bic)!=11)return INVALID_BIC_LENGTH;
   if((retval=lut_suche_bic(search_bic,cnt,NULL,NULL,NULL,NULL))==KEY_NOT_FOUND)retval=FALSE;
   return retval;
}

/* Funktion get_lut_info_b() +§§§1 */
/*
 * ######################################################################
 * # get_lut_info_b(): Infozeile der LUT-Datei holen, VB-Version        #
 * #                                                                    #
 * # Dies ist die Visual-Basic Version von get_lut_info() (s.u.). Die   #
 * # Funktion benutzt System.Text.StringBuilder, um einen Speicher-     #
 * # bereich in VB zu allokieren; dieser wird dann an C übergeben, der  #
 * # info-String kann einfach kopiert werden und der für prolog         #
 * # allokierte Speicher kann (hier) gleich wieder freigegeben werden.  #
 * ######################################################################
 */

DLL_EXPORT int get_lut_info_b(char **info_p,char *lutname)
{
   char *prolog,*info;
   int retval;

   if((retval=get_lut_info2(lutname,NULL,&prolog,&info,NULL))!=OK)RETURN(retval);
   if(info)
      strncpy(*info_p,info,1024);
   else
      **info_p=0;
   FREE(prolog);
   return OK;
}

DLL_EXPORT int get_lut_info2_b(char *lutname,int *version,char **prolog_p,char **info_p,char **user_info_p)
{
   char *prolog,*info,*user_info;
   int retval;

   if((retval=get_lut_info2(lutname,version,&prolog,&info,&user_info))!=OK)RETURN(retval);
   if(prolog){
      strncpy(*prolog_p,prolog,1024);
      FREE(prolog);
   }
   else
      **prolog_p=0;
   if(info){
      strncpy(*info_p,info,1024);
      FREE(info);
   }
   else
      **info_p=0;
   if(user_info){
      strncpy(*user_info_p,user_info,1024);
      FREE(user_info);
   }
   else
      **user_info_p=0;
   FREE(prolog);
   return OK;
}

/* Funktion get_lut_info() +§§§1 */
/*
 * ######################################################################
 * # get_lut_info(): Infozeile der LUT-Datei holen                      #
 * #                                                                    #
 * # Die Funktion holt die Infozeile(n) der LUT-Datei in einen          #
 * # statischen Speicherbereich und setzt die Variable info auf diesen  #
 * # Speicher. Diese Funktion wird erst ab Version 1.1 der LUT-Datei    #
 * # unterstützt.                                                       #
 * #                                                                    #
 * # Parameter:                                                         #
 * #    info:     Die Variable wird auf die Infozeile gesetzt           #
 * #    lut_name: Name der LUT-Datei                                    #
 * #                                                                    #
 * # Rückgabewerte:                                                     #
 * #    ERROR_MALLOC       kann keinen Speicher allokieren              #
 * #    NO_LUT_FILE        LUT-Datei nicht gefunden (Pfad falsch?)      #
 * #    FATAL_ERROR        kann die LUT-Datei nicht lesen               #
 * #    INVALID_LUT_FILE   Fehler in der LUT-Datei (Format, CRC...)     #
 * #    OK                 Erfolg                                       #
 * #                                                                    #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ######################################################################
 */

DLL_EXPORT int get_lut_info_t(char **info,char *lut_name,KTO_CHK_CTX *ctx)
{
   return get_lut_info(info,lut_name);
}

DLL_EXPORT int get_lut_info(char **info,char *lut_name)
{
   char *prolog,*ptr;
   int retval;

   if((retval=get_lut_info2(lut_name,NULL,&prolog,&ptr,NULL))!=OK)RETURN(retval);
   if(ptr){
      *info=(char *)malloc(strlen(ptr)+1);
      strcpy(*info,ptr);   /* Infozeile kopieren, damit prolog freigegeben werden kann */
   }
   else
      *info=NULL;
   FREE(prolog);
   return OK;
}

/* Funktion kc_alloc() und kc_free() +§§§1 */
/*
 * ######################################################################
 * # kc_alloc und kc_free(): Speicher allokieren, bzw. freigeben        #
 * #                                                                    #
 * # kc_alloc wird in C# benutzt, da es so einfacher ist, Speicher zu   #
 * # allokieren.                                                        #
 * #                                                                    #
 * # Die Funktion kc_free() ruft nur free() auf; sie wird vom Perl-Modul#
 * # und C# benötigt, da in KontoCheck.xs in strawberry perl (Windows)  #
 * # die Funktion free() auf die Perl-Version umdefiniert wird und damit#
 * # keinen Speicher freigeben kann, der von C aus allokiert wurde.     #
 * # Auch in C# ist die Speicherverwaltung nicht einfach möglich.       #
 * #                                                                    #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ######################################################################
 */

DLL_EXPORT void kc_free(char *ptr)
{
   if(ptr)free(ptr);
}

DLL_EXPORT void *kc_alloc(int size,int *retval)
{
   void *ptr;

   if(!(ptr=(void*)calloc(size,1)))
      *retval=ERROR_MALLOC;
   else
      *retval=OK;
   return ptr;
}

/* Funktion cleanup_kto() +§§§1 */
/* ###########################################################################
 * # cleanup_kto(): Speicher freigeben                                       #
 * # Diese Funktion ist Teil des alten Interfaces und wurde als Wrapper      #
 * # zu den neuen Routinen umgestellt.                                       #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int cleanup_kto_t(KTO_CHK_CTX *ctx)
{
   return cleanup_kto();
}

DLL_EXPORT int cleanup_kto(void)
{
   return lut_cleanup();
}

/* Funktion get_kto_check_version() +§§§1 */
/* ###########################################################################
 * #  Diese Funktion gibt die Version und das Datum der Kompilierung der     #
 * #  konto_check library als String zurück.                                .#
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *get_kto_check_version(void)
{
   return "konto_check Version " VERSION " vom " VERSION_DATE " (kompiliert " __DATE__ ", " __TIME__ ")";
}

DLL_EXPORT const char *get_kto_check_version_x(int mode)
{
      /* Arrays initialisieren, falls noch nicht gemacht */
   if(!(init_status&1))init_atoi_table();

   switch(mode){
      default:    /* 0 bzw. Default ist wie get_kto_check_version(), die Werte geben einzelne Felder zurück */
      case 0:
         return "konto_check Version " VERSION " vom " VERSION_DATE " (kompiliert " __DATE__ ", " __TIME__ ")";
      case 1:
         return VERSION;                   /* Versionsnummer */
      case 2:
         return VERSION_DATE;              /* Datum der Version */
      case 3:
         return __DATE__ ", " __TIME__;    /* Compilierdatum und -zeit */
      case 4:                              /* Datum der Prüfziffermethode */
#if 1
         if(pz_aenderungen_aktivieren)
            return "08.09.2014";
         else
            return "09.06.2014 (Aenderungen vom 08.09.2014 enthalten aber noch nicht aktiviert)";
#else
         return "08.09.2014";
#endif
      case 5:
        return "08.09.2014";
      case 6:
        return "1. September 2014";            /* Klartext-Datum der Bibliotheksversion */
      case 7:
        return "final";            /* Versions-Typ der Bibliotheksversion (development, beta, final) */
   }
}


/* Funktion dump_lutfile_p() +§§§1 */
/* ###########################################################################
 * # Diese Funktion dient dazu, Felder der **geladenen** LUT-Datei (in       #
 * # beliebiger Reihenfolge) auszugeben. Die auszugebenden Felder werden in  #
 * # dem Array required spezifiziert. Es werden nur Felder der Deutschen     #
 * # Bundesbank berücksichtigt; andere Felder werden ignoriert. Die Funktion #
 * # benutzt statt des Integerarrays einen Integerparameter, da diese        # 
 * # Variante vor allem für Perl gedacht ist; in der Umgebung ist es         #
 * # etwas komplizierter, ein Array zu übergeben.                            #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int dump_lutfile_p(char *outputname,UINT4 felder)
{
   UINT4 *felder1;

   switch(felder){
      case 0:  felder1=(UINT4 *)lut_set_o0; break;  
      case 1:  felder1=(UINT4 *)lut_set_o1; break;
      case 2:  felder1=(UINT4 *)lut_set_o2; break;
      case 3:  felder1=(UINT4 *)lut_set_o3; break;
      case 4:  felder1=(UINT4 *)lut_set_o4; break;
      case 5:  felder1=(UINT4 *)lut_set_o5; break;
      case 6:  felder1=(UINT4 *)lut_set_o6; break;
      case 7:  felder1=(UINT4 *)lut_set_o7; break;
      case 8:  felder1=(UINT4 *)lut_set_o8; break;
      case 9:  felder1=(UINT4 *)lut_set_o9; break;
      default: felder1=(UINT4 *)lut_set_o9; break;
   }
   return dump_lutfile(outputname,felder1);
}

/* Funktion dump_lutfile() +§§§1 */
/* ###########################################################################
 * # Diese Funktion dient dazu, Felder der **geladenen** LUT-Datei (in       #
 * # beliebiger Reihenfolge) auszugeben. Die auszugebenden Felder werden in  #
 * # dem Array required spezifiziert. Es werden nur Felder der Deutschen     #
 * # Bundesbank berücksichtigt; andere Felder werden ignoriert.              #
 * #                                                                         #
 * # Copyright (C) 2007 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int dump_lutfile(char *outputname,UINT4 *required)
{
   int i,i1,j=0,k,cnt,m,zeige_filialen;
   UINT4 xr[MAX_SLOTS];
   FILE *out;

   if(!blz)return LUT2_BLZ_NOT_INITIALIZED;
   if(!pz_methoden)return LUT2_PZ_NOT_INITIALIZED;
   zeige_filialen=0;
   if(!outputname)
      out=stderr;
   else if(!(out=fopen(outputname,"w"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen(w)");
      return FILE_WRITE_ERROR;
   }
   if(!required)
      for(required=xr,i=0;i<MAX_SLOTS;i++)xr[i]=i+1; /* Default: alle Blocks ausgeben */
   else{
      for(i=j=0;i<MAX_SLOTS && j<MAX_SLOTS && required[i];i++)if(required[i]==LUT2_NAME_NAME_KURZ){
         xr[j++]=LUT2_NAME;
         xr[j++]=LUT2_NAME_KURZ;
      }
      else if(i>0 && required[i]==LUT2_FILIALEN && required[i-1]==LUT2_FILIALEN)
         zeige_filialen=1;
      else
         xr[j++]=required[i];
   }
   xr[j]=0;
   if(current_info)
      fprintf(out,"Infoblock der Daten:\n====================\n%s\n",current_info);
   else if(lut_prolog)
      fprintf(out,"Prolog:\n=======\n%s\n",lut_prolog);
   for(i=cnt=0;(xr[cnt]);cnt++)switch(xr[cnt]){  /* Anzahl der Elemente im Array bestimmen und Überschriften ausgeben */
      case 1:
         fprintf(out,"%-8s ","BLZ");
         i+=9;
         break;
      case 2:
         fprintf(out,"%6s ","Filia.");
         i+=7;
         break;
      case 3:
         fprintf(out,"%-58s ","Bankname");
         i+=59;
         break;
      case 4:
         fprintf(out,"%-5s ","Plz");
         i+=6;
         break;
      case 5:
         fprintf(out,"%-35s ","Ort");
         i+=36;
         break;
      case 6:
         fprintf(out,"%-27s ","Bankname (kurz)");
         i+=28;
         break;
      case 7:
         fprintf(out,"%5s ","PAN");
         i+=6;
         break;
      case 8:
         fprintf(out,"%11s ","BIC");
         i+=12;
         break;
      case 9:
         fprintf(out,"%2s ","PZ");
         i+=3;
         break;
      case 10:
         fprintf(out,"%6s ","LfdNr");
         i+=7;
         break;
      case 11:
         fprintf(out,"%1s ","A");
         i+=2;
         break;
      case 12:
         fprintf(out,"%1s ","L");
         i+=2;
         break;
      case 13:
         fprintf(out,"%8s ","NachfBLZ");
         i+=9;
         break;
      case 14:
         fprintf(out,"%-58s ","Name, Kurzn.");
         i+=59;
         break;
      case 25:
         fprintf(out,"%6s ","IBAN Regel");
         i+=7;
         break;
      default:
         break;
   }
   fputc('\n',out);
   while(--i)fputc('=',out);
   fputc('\n',out);

   for(i=0;i<lut2_cnt_hs;i++){
      if(filialen && zeige_filialen)
         k=startidx[i]+filialen[i]-1;
      else
         k=startidx[i];
      for(i1=startidx[i];i1<=k;i1++){
         for(j=0;j<cnt;j++)switch(xr[j]){
            case LUT2_BLZ: 
               if(blz)fprintf(out,"%8d ",blz[i]);
               break;
            case LUT2_FILIALEN: 
               if(filialen){
                  if(i1==startidx[i]){
                     if(filialen[i]==1)
                        fprintf(out,"H      ");
                     else if(filialen[i]<11)
                        fprintf(out,"H  [%1d] ",filialen[i]-1);
                     else if(filialen[i]<101)
                        fprintf(out,"H [%2d] ",filialen[i]-1);
                     else
                        fprintf(out,"H[%3d] ",filialen[i]-1);
                  }
                  else
                     fprintf(out,"F %3d  ",i1-startidx[i]);
               }
               break;
            case LUT2_NAME: 
               if(name)fprintf(out,"%-58s ",name[i1]);
               break;
            case LUT2_PLZ: 
               if(plz)fprintf(out,"%5d ",plz[i1]);
               break;
            case LUT2_ORT: 
               if(ort)fprintf(out,"%-35s ",ort[i1]);
               break;
            case LUT2_NAME_KURZ: 
               if(name_kurz)fprintf(out,"%-27s ",name_kurz[i1]);
               break;
            case LUT2_PAN: 
               if(pan)fprintf(out,"%5d ",pan[i1]);
               break;
            case LUT2_BIC: 
               if(bic)fprintf(out,"%11s ",bic[i1]);
               break;
            case LUT2_PZ: 
               if(pz_methoden){
                  m=pz_methoden[i];
                  if(m<100)
                     fprintf(out,"%02d ",m);
                  else
                     fprintf(out,"%c%d ",m/10-10+'A',m%10);
               }
               break;
            case LUT2_NR: 
               if(bank_nr)fprintf(out,"%6d ",bank_nr[i1]);
               break;
            case LUT2_AENDERUNG: 
               if(aenderung)fprintf(out,"%c ",aenderung[i1]);
               break;
            case LUT2_LOESCHUNG: 
               if(loeschung)fprintf(out,"%c ",loeschung[i1]);
               break;
            case LUT2_NACHFOLGE_BLZ: 
               if(nachfolge_blz)fprintf(out,"%8d ",nachfolge_blz[i1]);
               break;
            default:
               break;
         }
         fputc('\n',out);
      }
   }
   if(outputname)fclose(out);
   return OK;
}

/* Funktion rebuild_blzfile() +§§§1 */
/* ###########################################################################
 * # Die Funktion rebuild_blzfile() ist ein Härtetest für die LUT2-Routinen: #
 * # die BLZ-Datei wird komplett aus einer LUT-Datei neu generiert.          #
 * # Es ist allerdings zu beachten, daß in der BLZ-Datei die Hauptstellen    #
 * # oft erst nach den Zweigstellen kommen, während sie in der LUT-Datei     #
 * # vor die Zweigstellen sortiert werden; außerdem werden die Zweigstellen  #
 * # in der LUT-Datei nach Postleitzahlen sortiert. Eine sortierte Version   #
 * # beider Dateien zeigt jedoch keine Unterschiede mehr.                    #
 * #                                                                         #
 * # Falls der Parameter set 1 oder 2 ist, wird als Eingabedatei eine LUT-   #
 * # datei erwartet; bei einem set-Parameter von 0 eine Klartextdatei        #
 * # (Bundesbankdatei).                                                      #
 * #                                                                         #
 * # Update 2014: die IBAN-Regeln werden jetzt auch ausgegeben.              #
 * #                                                                         #
 * # Copyright (C) 2007,2009 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

DLL_EXPORT int rebuild_blzfile(char *inputname,char *outputname,UINT4 set)
{
   char pbuf[256],*b,pan_buf[8],nr_buf[8],tmpfile[16];
   char  **p_name,**p_name_kurz,**p_ort,**p_bic,*p_aenderung,*p_loeschung;
   int i,j,ret,regel;
   int cnt,*p_nachfolge_blz,id,p_pz,*p_nr,*p_plz,*p_pan;
   UINT4 lut_set[30];
   FILE *out;
   struct stat s_buf;

   if(!set){ /* set-Parameter 0: BLZ-Datei (Klartext) als Eingabedatei, LUT-Datei generieren */

         /* eigene Version von mktemp, da die Libraryversion immer einen Linkerfehler
          * erzeugt, der sich nicht deaktivieren läßt (ist hier auch nicht kritisch)
          */
      for(i=0;i<100000;i++){
         sprintf(tmpfile,"blz_tmp.%05d",i);
         if((stat(tmpfile,&s_buf)==-1) && (errno==EBADF || errno==ENOENT))break;
      }
      lut_set[0]=LUT2_BLZ;
      lut_set[1]=LUT2_PZ;
      lut_set[2]=LUT2_FILIALEN;
      for(i=0;(lut_set[i+3]=lut_set_9[i]) && i<28;i++);
      lut_set[i+3]=0;
      if(i==100000)return FATAL_ERROR; /* keine mögliche Ausgabedatei gefunden */
      ret=generate_lut2(inputname,tmpfile,"Testdatei fuer LUT2",NULL,lut_set,20,3,0);
      if(ret<=0){
         unlink(tmpfile);
         RETURN(ret);
      }
      ret=kto_check_init_p(tmpfile,9,0,0);
      unlink(tmpfile);
      if(ret<=0)RETURN(ret);
   }
   else  /* set-Parameter 1 oder 2: LUT-Datei als Eingabedatei */
      if(set<0)   /* set darf nur 0, 1 oder 2 sein; 0 wurde schon behandelt */
         set=1;
      else if(set>2)
         set=2;
      if((ret=kto_check_init_p(inputname,9,set,0))<=0)RETURN(ret);

   if(!(out=fopen(outputname,"w"))){
      PRINT_VERBOSE_DEBUG_FILE("fopen");
      return FILE_WRITE_ERROR;
   }
   for(i=regel=0;i<lut2_cnt_hs;i++){
      sprintf(b=pbuf,"%d",blz[i]);
      lut_multiple(pbuf,&cnt,NULL,&p_name,&p_name_kurz,&p_plz,&p_ort,&p_pan,&p_bic,
            &p_pz,&p_nr,&p_aenderung,&p_loeschung,&p_nachfolge_blz,&id,NULL,NULL);
      if(*p_pan)
         sprintf(pan_buf,"%05d",*p_pan);
      else
         *pan_buf=0;
      if(*p_nr)
         sprintf(nr_buf,"%06d",*p_nr);
      else
         *nr_buf=0;
      fprintf(out,"%8s1%-58s%05d%-35s%-27s%5s%-11s%X%d%6s%c%c%08d",
            pbuf,*p_name,*p_plz,*p_ort,*p_name_kurz,pan_buf,*p_bic,p_pz/10,p_pz%10,
            nr_buf,*p_aenderung,*p_loeschung,*p_nachfolge_blz);
      if(iban_regel){
         regel=lut_iban_regel(pbuf,0,NULL);
         fprintf(out,"%06d\n",regel);
      }
      else
         fputc('\n',out);
      for(j=1;j<cnt;j++){
         if(p_pan[j])
            sprintf(pan_buf,"%05d",p_pan[j]);
         else
            *pan_buf=0;
         if(p_nr[j])
            sprintf(nr_buf,"%06d",p_nr[j]);
         else
            *nr_buf=0;
         fprintf(out,"%8s2%-58s%05d%-35s%-27s%5s%-11s%X%d%6s%c%c%08d",
               pbuf,p_name[j],p_plz[j],p_ort[j],p_name_kurz[j],pan_buf,p_bic[j],
               p_pz/10,p_pz%10,nr_buf,p_aenderung[j],p_loeschung[j],p_nachfolge_blz[j]);
         if(iban_regel)
            fprintf(out,"%06d\n",regel);
         else
            fputc('\n',out);
      }
   }
   fclose(out);
   return OK;
}

/* Funktion iban2bic() +§§§1 */
/* ###########################################################################
 * # Die Funktion iban2bic extrahiert aus einer IBAN (International Bank     #
 * # Account Number) Kontonummer und Bankleitzahl, und bestimmt zu der BLZ   #
 * # den zugehörigen BIC. Voraussetzung ist natürlich, daß das BIC Feld in   #
 * # der geladenen LUT-Datei enthalten ist. BLZ und Kontonummer werden,      #
 * # falls gewünscht, in zwei Variablen zurückgegeben.                       #
 * #                                                                         #
 * # Die Funktion arbeitet nur für deutsche Banken, da für andere keine      #
 * # Infos vorliegen.                                                        #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    iban:       die IBAN, zu der die Werte bestimmt werden sollen        #
 * #    retval:     NULL oder Adresse einer Variablen, in die der Rückgabe-  #
 * #                wert der Umwandlung geschrieben wird                     #
 * #    blz:        NULL, oder Adresse eines Speicherbereichs mit mindestens #
 * #                9 Byte, in den die BLZ geschrieben wird                  #
 * #    kto:        NULL, oder Adresse eines Speicherbereichs mit mindestens #
 * #                11 Byte, in den die Kontonummer geschrieben wird.        #
 * #                                                                         #
 * # Rückgabe:      der zu der übergebenen IBAN gehörende BIC                #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *iban2bic(char *iban,int *retval,char *blz,char *kto)
{
   char iban1[64],*ptr,*dptr,blz2[16],kto2[16],*papier,iban2[64];
   const char *bic;
   int i,j,ret,uk,regel;

      /* alle Leerzeichen aus der IBAN entfernen */
   for(ptr=iban,dptr=iban1;*ptr;ptr++)if(isalnum(*ptr))*dptr++=*ptr;
   *dptr=0;
   iban=iban1;

   if(tolower(*iban)!='d' || tolower(*(iban+1))!='e'){
      if(retval)*retval=IBAN2BIC_ONLY_GERMAN;
      if(blz)*blz=0;
      if(kto)*kto=0;
      return "";
   }
   if(strlen(iban)!=22){
      if(retval)*retval=INVALID_IBAN_LENGTH;
      return "";
   }

   for(ptr=iban+4,dptr=blz2,i=0;i<8;ptr++)if(isdigit(*ptr)){
      *dptr++=*ptr;
      i++;
   }
   *dptr++=0;
   for(dptr=kto2,i=0;i<10;ptr++)if(isdigit(*ptr)){
      *dptr++=*ptr;
      i++;
   }
   *dptr=0;
   if(blz){
      for(ptr=iban+4,dptr=blz,i=0;i<8;ptr++)if(isdigit(*ptr)){
         *dptr++=*ptr;
         i++;
      }
      *dptr=0;
   }
   if(kto){
      for(dptr=kto,i=0;i<10;ptr++)if(isdigit(*ptr)){
         *dptr++=*ptr;
         i++;
      }
      *dptr=0;
   }
      /* Nachsehen, ob der BIC evl. durch eine Regel geändert wird
       * (ähnlich wie bei iban_check()).
       *
       * Prüfziffermethode und IBAN-Regel auf dem kleinen Dienstweg holen (es
       * müssen nicht alle Tests doppelt und dreifach gemacht werden ;-) Dann
       * testen, ob eine selbst generierte IBAN (mit Regeln und Unterkonto-
       * Ersetzung) mit der übergebenen Variante übereinstimmt, falls nicht,
       * Fehlermeldung/Warnung. Falls eine Regel benutzt wird, wird der BIC aus
       * iban_bic_gen() genommen, ansonsten der aus lut_bic().
       */
   if(retval)*retval=OK;
   if((j=lut_index(blz2))<=0){
      if(retval)*retval=j;
      return "";
   }
   if(j>0){
      uk=uk_pz_methoden[pz_methoden[j]];
      if(iban_regel)
         regel=iban_regel[startidx[j]];
      else
         regel=0;
      if(uk || regel){
         papier=iban_bic_gen(blz2,kto2,&bic,NULL,NULL,&ret);
         if(retval)*retval=ret;
         if(ret==NO_IBAN_CALCULATION){
            if(retval)*retval=OK;
            return bic;   /* kein IBAN berechnet, gleich zurück */
         }
         if(papier){
            for(ptr=papier,dptr=iban2;*ptr;ptr++)if(*ptr!=' ')*dptr++=*ptr;
            *dptr=0;
            FREE(papier);
            if(strcasecmp(iban,iban2) && retval){
               if(regel>0)
                  *retval=IBAN_CHKSUM_OK_RULE_IGNORED;
               else  /*  bei Regel==0 kann nur ein Unterkonto fehlen */
                  *retval=IBAN_CHKSUM_OK_UNTERKTO_MISSING;
            }
         }
         return bic;
      }
   }
   bic=lut_bic(blz2,0,retval);
   if(!strncmp(bic,"        ",8))bic="";
   return bic;
}

/* Funktion iban2bic_id() +§§§1 */
/* ###########################################################################
 * # Die Funktion iban2bic_id() entspricht der Funktion iban2bic(); für      #
 * # die Parameter blz und kto wird allerdings Speicher allokiert und per    #
 * # Handle wieder zurückgegeben.                                            #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *iban2bic_id(char *iban,int *retval,int *blz,int *kto)
{
   char *b,*k;

   if(!(b=(char*)malloc(12)) || !(k=(char*)malloc(12)) || kc_ptr2id(b,blz,1)<0 || kc_ptr2id(k,kto,1)<0){
      if(retval)*retval=ERROR_MALLOC;
      return "";
   }
   return iban2bic(iban,retval,b,k);
}

/* Funktion iban_gen(), iban_bic_gen() und iban_bic_gen1 +§§§1 */
/* ###########################################################################
 * # Die Funktion iban_gen generiert aus Bankleitzahl und Kontonummer eine   #
 * # IBAN (International Bank Account Number). Die Funktion ist lediglich    #
 * # zum Test der anderen IBAN-Routinen geschrieben, und sollte nicht zum    #
 * # Generieren realer IBANs benutzt werden (s.u.).                          #
 * #                                                                         #
 * # Update Juni 2011:                                                       #
 * # Es wird die Verbotsliste der Sparkassen ausgewertet, so daß für         #
 * # Institute, die einer Selbstberechnung nicht zugestimmt haben, keine     #
 * # IBAN berechnet wird. Damit dürften die Berechnungen (falls die "rote    #
 * # Liste" in der LUT-Datei vorhanden ist und ausgewertet wird) doch        #
 * # brauchbar sein.                                                         #
 * #                                                                         #
 * # Update Mai 2013:                                                        #
 * # Von der Bundesbank sind jetzt die IBAN-Regeln veröffentlicht, so daß    #
 * # eine zuverlässige Berechnung der IBAN in den meisten Fällen möglich     #
 * # ist. Bei einer Reihe Banken wird in der IBAN-Regel die BLZ, und manch-  #
 * # mal auch die Kontonummer durch einen anderen Wert ersetzt, wodurch      #
 * # sich natürlich auch der BIC ändert. Daher gibt es zusätzlich zu der     #
 * # alten Funktion iban_gen() jetzt noch eine weitere Funktion              #
 * # iban_bic_gen(), bei der in drei zusätzlichen Parametern noch der BIC    #
 * # sowie die benutzte BLZ und Kontonummer zurückgegeben wird (es ließe     #
 * # sich auch mit der Funktion iban2bic() machen, aber so hat man nur einen #
 * # einzigen Funktionsaufruf dafür).                                        #
 * #                                                                         #
 * # Die Funktion iban_bic_gen1() entspricht der Funktion iban_bic_gen(),    #
 * # nur werden die neue Kontonummer und BLZ nicht zurückgegeben. Diese      #
 * # Funktion wird für VC# und VB.net benutzt, um die Parameterübergabe      #
 * # möglich zu machen.                                                      #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    blz:        Bankleitzahl. Falls der Bankleitzahl ein + vorangestellt #
 * #                wird, wird die entsprechende Bankverbindung nicht auf    #
 * #                Korrektheit getestet (ansonsten schon; dies ist zum      #
 * #                Debuggen der konto_check Bibliothek gedacht).            #
 * #                                                                         #
 * #                Falls der Bankleitzahl ein @ vorangestellt wird, wird    #
 * #                nicht geprüft, ob die Bank einer Selbstberechnung der    #
 * #                IBAN zugestimmt hat. Das Ergebnis kann dann u.U. fehler- #
 * #                haft sein.                                               #
 * #                                                                         #
 * #    blz2:       Für die Generierung der IBAN benutzte BLZ. Die BLZ wird  #
 * #                durch viele IBAN-Regeln geändert und wird in dieser      #
 * #                Variablen zurückgegeben. Für die Variable muß die        #
 * #                aufrufende Funktion Speicher bereitstellen (z.B. ein     #
 * #                lokales char-Array), der Wert für blz2 wird nur in       #
 * #                den angegebenen Speicher kopiert. Falls für die Variable #
 * #                NULL übergeben wird, wird sie ignoriert.                 #
 * #                                                                         #
 * #                                                                         #
 * #    kto2:       Für die Generierung der IBAN benutzte Kontonummer. Auch  #
 * #                die Kontonummmer wird von manchen Regeln geändert; die   #
 * #                benutzte Kontonummer kann mit dieser Variablen ermittelt #
 * #                werden. Der Speicher muß ebenfalls von der aufrufenden   #
 * #                Funktion bereitgestellt werden. Falls für die Variable   #
 * #                NULL übergeben wird, wird sie ignoriert.                 #
 * #                                                                         #
 * #    bic:        NULL oder Adresse einer Variablen, in die der aktuelle   #
 * #                BIC geschrieben wird (nur bei iban_bic_gen() ).          #
 * #                                                                         #
 * #    kto:        Kontonummer                                              #
 * #    retval:     NULL oder Adresse einer Variablen, in die der Rückgabe-  #
 * #                wert der Kontoprüfung geschrieben wird                   #
 * #                                                                         #
 * # Rückgabe:      die erzeugte IBAN. Für die Rückgabe wird Speicher        #
 * #                allokiert; dieser muß nach der Benutzung wieder frei-    #
 * #                gegeben werden. Falls der Test der Bankverbindung        #
 * #                fehlschlägt, wird der entsprechende Fehlercode in die    #
 * #                Variable retval geschrieben und NULL zurückgegeben.      #
 * #                                                                         #
 * # Copyright (C) 2008,2013 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

DLL_EXPORT char *iban_gen(char *blz,char *kto,int *retval)
{
   return iban_bic_gen(blz,kto,NULL,NULL,NULL,retval);
}

DLL_EXPORT int iban_gen_id(char *blz,char *kto,int *retval)
{
   char *ptr;
   int rv,id;

   if(!(ptr=iban_bic_gen(blz,kto,NULL,NULL,NULL,retval)))return -1;  /* retval wurde in iban_bic_gen gesetzt, daher gleich return */
   if((rv=kc_ptr2id(ptr,&id,1))<0){
      *retval=rv;
      return -1;
   }
   return id;
}

DLL_EXPORT int iban_bic_gen_id(char *blz,char *kto,int *bic2,int *blz2,int *kto2,int *retval)
{
   char *ptr,*bp2,*b2,*k2;
   const char *bp;
   int rv,id;

   bp2=b2=k2=NULL;
   if(!(bp2=(char*)malloc(16)) || !(b2=(char*)malloc(16)) || !(k2=(char*)malloc(16))){
      FREE(bp2);
      FREE(b2);
      FREE(k2);
      return ERROR_MALLOC;
   }
   ptr=iban_bic_gen(blz,kto,&bp,b2,k2,retval);
   strcpy(bp2,(char*)bp);
   if((rv=kc_ptr2id(bp2,bic2,1))<0 || (rv=kc_ptr2id(b2,blz2,1))<0 || (rv=kc_ptr2id(k2,kto2,1))<0){
      FREE(bp2);
      FREE(b2);
      FREE(k2);
      *retval=rv;
      return -1;
   }

   if(!ptr)return -1;   /* Fehler bei der Generierung */
   if((rv=kc_ptr2id(ptr,&id,1))<0){
      *retval=rv;
      return -1;
   }
   return id;
}

DLL_EXPORT char *iban_bic_gen1(char *blz,char *kto,const char **bicp,int *retval)
{
   return iban_bic_gen(blz,kto,bicp,NULL,NULL,retval);
}

DLL_EXPORT char *iban_bic_gen(char *blz,char *kto,const char **bicp,char *blz2,char *kto2,int *retval)
{
   char c,check[128],iban[128],kto_n[16],blz_n[12],*ptr,*dptr;
   const char *bic;
   int j,ret,ret_regel,blz_i,flags,regel;
#if !USE_IBAN_RULES
   int uk_cnt=-1;
#endif
   UINT4 zahl,rest;

   if(bicp)*bicp=NULL;
   bic=NULL;
   if(!blz || !kto || !*blz || !*kto){
      if(retval)*retval=LUT2_NO_ACCOUNT_GIVEN;
      if(blz2)*blz2=0;
      if(kto2)*kto2=0;
      return NULL;
   }

   if((ret=iban_init())<OK){  /* alle notwendigen Blocks kontrollieren, evl. nachladen */
      if(retval)*retval=ret;
      return NULL;
   }

   for(flags=0,ptr=blz;!isdigit(*ptr);ptr++){
      if(*ptr=='+')flags+=1;  /* Bankverbindung nicht testen */
      if(*ptr=='@')flags+=2;  /* "schwarze Liste" (CONFIG.INI bzw. iban.blacklist) nicht auswerten */
      if(*ptr=='!')flags+=4;  /* BLZ nicht durch Nachfolge-BLZ ersetzen */
   }
   while(*blz=='@' || *blz=='+' || *blz=='!')blz++;

   if(blz2)strcpy(blz2,blz);
   if(kto2)strcpy(kto2,kto);

      /* BLZ numerisch darstellen */
   blz_i=b8[I blz[0]]+b7[I blz[1]]+b6[I blz[2]]+b5[I blz[3]]+b4[I blz[4]]+b3[I blz[5]]+b2[I blz[6]]+b1[I blz[7]];

      /* BLZ und Kontonummer in eigenen Speicherbereich kopieren, Konto links mit Nullen füllen */
#if USE_IBAN_RULES
   for(ptr=blz,dptr=blz_n;(*dptr++=*ptr++););
   for(ptr=kto;*ptr;ptr++);   /* Ende von kto suchen */
   ptr--;
   memcpy(kto_n,"0000000000",10);
   kto_n[10]=0;
   for(dptr=kto_n+9;ptr>=kto;)*dptr--=*ptr--;
   kto=kto_n;
   blz=blz_n;

   regel=lut_iban_regel_i(blz_i,0,&ret);
   if(ret<=0 && ret!=LUT2_IBAN_REGEL_NOT_INITIALIZED){
      if(retval)*retval=ret;
      return NULL;
   }
   if(ret!=LUT2_IBAN_REGEL_NOT_INITIALIZED){

         /* testen, ob die BLZ in der "Verbotsliste" steht und keine Regel spezifiziert wurde */
      if(regel==0 && !(flags&2) && own_iban && *own_iban==2718281){
         if(bsearch(&blz_i,own_iban,own_iban_cnt,sizeof(int),cmp_int)){
            if(retval)*retval=BLZ_BLACKLISTED;
            return NULL;
         }
      }

         /* IBAN-Regeln anwenden; u.U. wird BLZ und/oder Konto ersetzt */
      if((ret_regel=iban_regel_cvt(blz,kto,&bic,regel,NULL))<OK){
         if(!bic)bic=lut_bic(blz,0,NULL);
         if(!strncmp(bic,"        ",8))bic="";
         if(retval)*retval=ret_regel;
         if(bicp)*bicp=bic;
         if(blz2)strcpy(blz2,blz);  /* evl. sind BLZ und Konto schon ersetzt; zurückgeben */
         if(kto2)strcpy(kto2,kto);
         return NULL;
      }
   }
   else{ /* Block mit IBAN-Regeln nicht geladen; Regel 0 verwenden (keine Warnung) */
      regel=0;
      ret_regel=OK;
   }
   if(ret_regel==OK_IBAN_WITHOUT_KC_TEST || ret_regel==OK_KTO_REPLACED_NO_PZ)flags|=1; /* kein Test der Bankverbindung */
#else
   ret_regel=OK;
   if(!(flags&2) && own_iban){
         /* testen, ob die BLZ in der "Verbotsliste" steht */
      if(bsearch(&blz_i,own_iban,own_iban_cnt,sizeof(int),cmp_int)){
         if(retval)*retval=NO_OWN_IBAN_CALCULATION;
         return NULL;
      }
   }
#endif

      /* IBAN-Regel 0000 00: BLZ durch Nachfolge-BLZ ersetzen, falls eine
       * solche existiert. Für einige Konten wird die BLZ auch in den
       * IBAN-Regeln ersetzt (bei Regel 31-35 werden sogar für verschiedene
       * Kontokreise einer BLZ unterschiedliche Nachfolge-BLZs vorgeschrieben).
       * Die Werte der IBAN-Regeln haben Vorrang vor denen der Bundesbankdatei,
       * daher darf der Test auf die Nachfolge-BLZ erst nach den IBAN-Regeln
       * erfolgen.
       */
   blz_i=lut_nachfolge_blz(blz,0,&ret);
   if(regel==0 && !(flags&4) && ret==OK && blz_i>0){
      int ret_old,ret_neu;

      ret_old=kto_check(blz,kto,NULL); /* alte Bankverbindung testen */
      sprintf(blz=blz_n,"%8d",blz_i);
      ret_neu=kto_check(blz,kto,NULL)  /* neue BLZ, altes Konto testen */;
      if(ret_old==OK && ret_neu<OK){  /* u.U. andere Prüfziffermethode; Konten müssen dann angepasst werden */
         if(retval)*retval=OLD_BLZ_OK_NEW_NOT;
         return NULL;
      }
   }
   else
      blz_i=atoi(blz);  /* keine Nachfolge-BLZ */

      /* nun dürfte die BLZ endgültig sein; bei Bedarf den BIC bestimmen, falls
       * gefordert und noch nicht gemacht. Ebenso werden nun die benutzte BLZ
       * und Kontonummer eingetragen.
       */
   if(bicp){
      if(!bic)bic=lut_bic(blz,0,NULL);
      if(!strncmp(bic,"        ",8))bic="";
      *bicp=bic;
   }
   if(blz2)strcpy(blz2,blz);
   if(kto2)strcpy(kto2,kto);

      /* erstmal das Konto testen */
   if(!(flags&1)){  /* Test der Bankverbindung */
#if USE_IBAN_RULES
      if((ret=kto_check_blz(blz,kto))<=0){   /* Konto fehlerhaft */
         if(retval)*retval=ret;
         return NULL;
      }
#else
      if((ret=kto_check_blz_x(blz,kto,&uk_cnt))<=0){  /* Konto fehlerhaft */
         if(retval)*retval=ret;
         return NULL;
      }

         /* bei einigen Methoden (13, 26, 50, 63, 76 und C7) kann u.U. ein
          * Unterkonto weggelassen worden sein. Näheres dazu in der Funktion
          * kto_check_blz_x().
          *
          * *** (alter Code, mit den IBAN-Regeln ist dieser Kommentar nicht mehr aktuell) ***
          * Falls dies der Fall war (uk_cnt>0) wird es hier wieder an der
          * richtigen Stelle eingefügt; es wird allerdings als Fehler angesehen
          * (mit dem Fehlercode OK_UNTERKONTO_ATTACHED). Falls ein Unterkonto
          * möglich bzw. angegeben ist, ist das normalerweise ein Zeichen dafür
          * daß das betreffende Institut einer Selbstberechnung nicht zugestimmt
          * hat; es wird dann nur eine Warnung ausgegeben (OK_UNTERKONTO_POSSIBLE
          * bzw. OK_UNTERKONTO_GIVEN), aber diese Werte sind größer als 0 und
          * werden insofern nicht als Fehler gerechnet. Das Ergebnis kann
          * allerdings u.U. falsch sein und sollte mit Vorsicht benutzt werden.
          */
      if(uk_cnt>0){
         for(ptr=kto,dptr=kto_n;(*dptr=*ptr++);dptr++);
         *dptr++='0';
         if(uk_cnt>1)*dptr++='0';
         if(uk_cnt>2)*dptr++='0';
         *dptr=0;
         if((ret=kto_check_blz(blz,kto_n))>0){   /* Unterkonto muß angehängt werden */
            kto=kto_n;
            ret_regel=OK_UNTERKONTO_ATTACHED;
         }
      }
      else if(!uk_cnt){
         ret_regel=OK_UNTERKONTO_POSSIBLE;
      }
      else if(uk_cnt==-1){
         ret_regel=OK_UNTERKONTO_GIVEN;
      }
      else{ /* uk_cnt==-2 */
         ret_regel=OK;
      }
#endif
   }
   else
      if(ret_regel!=OK_IBAN_WITHOUT_KC_TEST && ret_regel!=OK_KTO_REPLACED_NO_PZ)ret_regel=LUT2_KTO_NOT_CHECKED;

   sprintf(iban,"DE00%8s%10s",blz,kto);
   for(ptr=iban;*ptr;ptr++)if(*ptr==' ')*ptr='0';
   for(ptr=iban+4,dptr=check;*ptr;ptr++){
      if((c=*ptr)>='0' && c<='9')
         *dptr++=c;
      else if(c>='A' && c<='Z'){
         c+=10-'A';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
      else if(c>='a' && c<='z'){
         c+=10-'a';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
   }

      /* Ländercode (2-stellig/alphabetisch) kopieren */
   ptr=iban;
   if((c=*ptr++)>='A' && c<='Z'){
      c+=10-'A';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   else if(c>='a' && c<='z'){
      c+=10-'a';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   if((c=*ptr++)>='A' && c<='Z'){
      c+=10-'A';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   else if(c>='a' && c<='z'){
      c+=10-'a';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }

      /* Prüfziffer kopieren */
   *dptr++=*ptr++;
   *dptr++=*ptr++;
   *dptr=0;

   for(rest=0,ptr=check;*ptr;){
      zahl=rest/10;
      zahl=zahl*10+rest%10;
      for(j=0;j<6 && *ptr;ptr++,j++)zahl=zahl*10+ *ptr-'0';
      rest=zahl%97;
   }
   zahl=98-rest;
   *(iban+2)=zahl/10+'0';
   *(iban+3)=zahl%10+'0';
   for(ptr=iban,dptr=check,j=1;*ptr;j++){
      *dptr++=*ptr++;
      if(j>0 && !(j%4))*dptr++=' ';
   }
   *dptr=0;
   ptr=(char *)malloc(64);
   strcpy(ptr,check);
   if(retval)*retval=ret_regel;
   return ptr;
}

/* Funktion ci_check() +§§§1 */
/* ###########################################################################
 * # Die Funktion ci_check testet die Prüfsumme eines Creditor Identifiers   # 
 * # (Gläubiger-Identifikationsnummer)                                       #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    ci:         Creditor Identifiers der getestet werden soll            #
 * #                                                                         #
 * # Copyright (C) 2013 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int ci_check(char *ci)
{
   char c,check[128],ci1[64],*ptr,*dptr;
   int j;
   UINT4 zahl,rest;

   if(!ci)return MISSING_PARAMETER;

      /* alle Leerzeichen aus dem ci entfernen */
   for(ptr=ci,dptr=ci1;*ptr;ptr++)if(isalnum(*ptr))*dptr++=*ptr;
   *dptr=0;
   ci=ci1;


      /* BBAN (Basic Bank Account Number) kopieren (alphanumerisch) */
   for(ptr=ci+7,dptr=check;*ptr;ptr++){
      if((c=*ptr)>='0' && c<='9')
         *dptr++=c;
      else if(c>='A' && c<='Z'){
         c+=10-'A';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
      else if(c>='a' && c<='z'){
         c+=10-'a';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
   }

      /* Ländercode (2-stellig/alphabetisch) kopieren */
   ptr=ci;
   if((c=*ptr++)>='A' && c<='Z'){
      c+=10-'A';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   else if(c>='a' && c<='z'){
      c+=10-'a';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   if((c=*ptr++)>='A' && c<='Z'){
      c+=10-'A';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   else if(c>='a' && c<='z'){
      c+=10-'a';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }

      /* Prüfziffer kopieren */
   *dptr++=*ptr++;
   *dptr++=*ptr++;
   *dptr=0;

   for(rest=0,ptr=check;*ptr;){
      zahl=rest/10;
      zahl=zahl*10+rest%10;
      for(j=0;j<6 && *ptr;ptr++,j++)zahl=zahl*10+ *ptr-'0';
      rest=zahl%97;
   }
   zahl=98-rest;
   if(rest==1)
      return OK;
   else
      return FALSE; 
}

/* Funktion iban_check() +§§§1 */
/* ###########################################################################
 * # Die Funktion iban_check prüft, ob die Prüfsumme des IBAN ok ist und     #
 * # testet außerdem noch die BLZ/Konto Kombination. Für den Test des Kontos #
 * # wird keine Initialisierung gemacht; diese muß vorher erfolgen.          #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    iban:       IBAN die getestet werden soll                            #
 * #    retval:     NULL oder Adresse einer Variablen, in die der Rückgabe-  #
 * #                wert der Kontoprüfung geschrieben wird                   #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int iban_check(char *iban,int *retval)
{
   char c,check[128],*papier2,iban1[64],iban2[24],*blz2,*kto2,*ptr,*dptr;
   int j,test,ret,ret_kc=0,iban_len,regel,uk,nachfolge;
   UINT4 zahl,rest;

   if(!iban || !*iban){
      if(retval)*retval=LUT2_NO_ACCOUNT_GIVEN;
      return LUT2_NO_ACCOUNT_GIVEN;
   }

      /* alle Leerzeichen aus der IBAN entfernen */
   for(ptr=iban,dptr=iban1;*ptr;ptr++)if(isalnum(*ptr))*dptr++=*ptr;
   *dptr=0;
   iban=iban1;

      /* IBAN-Länge testen (abhängig vom Ländercode) */
   ptr=iban;
   if(*ptr>='a' && *ptr<='z')
      test=(*ptr-'a'+1)*100; 
   else if(*ptr>='A' && *ptr<='Z')
      test=(*ptr-'A'+1)*100;
   else
      test=0;

   ptr++;
   if(*ptr>='a' && *ptr<='z')
      test+=(*ptr-'a'+1); 
   else if(*ptr>='A' && *ptr<='Z')
      test+=(*ptr-'A'+1);
   for(iban_len=2,ptr++;*ptr;ptr++)if(isalnum(*ptr))iban_len++;

   if(retval)*retval=LUT2_KTO_NOT_CHECKED;
   switch(test){  /* Länge der IBAN testen, u.U. Fehler zurückgeben */
      case  112: if(iban_len!=28)return INVALID_IBAN_LENGTH; break; /* AL -> Albanien */
      case  104: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* AD -> Andorra */
      case  126: if(iban_len!=28)return INVALID_IBAN_LENGTH; break; /* AZ -> Aserbaidschan */
      case  208: if(iban_len!=22)return INVALID_IBAN_LENGTH; break; /* BH -> Bahrain */
      case  218: if(iban_len!=29)return INVALID_IBAN_LENGTH; break; /* BR -> Brasilien */
      case  205: if(iban_len!=16)return INVALID_IBAN_LENGTH; break; /* BE -> Belgien */
      case  201: if(iban_len!=20)return INVALID_IBAN_LENGTH; break; /* BA -> Bosnien und Herzegowina */
      case  207: if(iban_len!=22)return INVALID_IBAN_LENGTH; break; /* BG -> Bulgarien */
      case  318: if(iban_len!=21)return INVALID_IBAN_LENGTH; break; /* CR -> Costa Rica */
      case  411: if(iban_len!=18)return INVALID_IBAN_LENGTH; break; /* DK -> Dänemark */
      case  405: if(iban_len!=22)return INVALID_IBAN_LENGTH; break; /* DE -> Deutschland */
      case  415: if(iban_len!=28)return INVALID_IBAN_LENGTH; break; /* DO -> Dominikanische Republik */
      case  505: if(iban_len!=20)return INVALID_IBAN_LENGTH; break; /* EE -> Estland */
      case  615: if(iban_len!=18)return INVALID_IBAN_LENGTH; break; /* FO -> Färöer */
      case  609: if(iban_len!=18)return INVALID_IBAN_LENGTH; break; /* FI -> Finnland */
      case  618: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* FR -> Frankreich */
      case  706: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* GF -> Französisch-Guayana */
      case 1606: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* PF -> Französisch-Polynesien */
      case 2006: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* TF -> Französische Süd- und Antarktisgebiete */
      case  705: if(iban_len!=22)return INVALID_IBAN_LENGTH; break; /* GE -> Georgien */
      case  709: if(iban_len!=23)return INVALID_IBAN_LENGTH; break; /* GI -> Gibraltar */
      case  718: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* GR -> Griechenland */
      case  712: if(iban_len!=18)return INVALID_IBAN_LENGTH; break; /* GL -> Grönland */
      case  716: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* GP -> Guadeloupe */
      case  720: if(iban_len!=28)return INVALID_IBAN_LENGTH; break; /* GT -> Guatemala */
      case  811: if(iban_len!=16)return INVALID_IBAN_LENGTH; break; /* HK -> Hongkong */
      case  905: if(iban_len!=22)return INVALID_IBAN_LENGTH; break; /* IE -> Irland */
      case  919: if(iban_len!=26)return INVALID_IBAN_LENGTH; break; /* IS -> Island */
      case  912: if(iban_len!=23)return INVALID_IBAN_LENGTH; break; /* IL -> Israel */
      case  920: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* IT -> Italien */
      case 2207: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* VG -> Jungferninseln */
      case 1126: if(iban_len!=20)return INVALID_IBAN_LENGTH; break; /* KZ -> Kasachstan */
      case 1701: if(iban_len!=29)return INVALID_IBAN_LENGTH; break; /* QA -> Katar */
      case  818: if(iban_len!=21)return INVALID_IBAN_LENGTH; break; /* HR -> Kroatien */
      case 1123: if(iban_len!=30)return INVALID_IBAN_LENGTH; break; /* KW -> Kuwait */
      case 1222: if(iban_len!=21)return INVALID_IBAN_LENGTH; break; /* LV -> Lettland */
      case 1202: if(iban_len!=28)return INVALID_IBAN_LENGTH; break; /* LB -> Libanon */
      case 1209: if(iban_len!=21)return INVALID_IBAN_LENGTH; break; /* LI -> Liechtenstein */
      case 1220: if(iban_len!=20)return INVALID_IBAN_LENGTH; break; /* LT -> Litauen */
      case 1221: if(iban_len!=20)return INVALID_IBAN_LENGTH; break; /* LU -> Luxemburg */
      case 1320: if(iban_len!=31)return INVALID_IBAN_LENGTH; break; /* MT -> Malta */
      case 1301: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* MA -> Marokko */
      case 1317: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* MQ -> Martinique */
      case 1318: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* MR -> Mauretanien */
      case 1321: if(iban_len!=30)return INVALID_IBAN_LENGTH; break; /* MU -> Mauritius */
      case 2520: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* YT -> Mayotte */
      case 1311: if(iban_len!=19)return INVALID_IBAN_LENGTH; break; /* MK -> Mazedonien */
      case 1304: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* MD -> Moldawien */
      case 1303: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* MC -> Monaco */
      case 1305: if(iban_len!=22)return INVALID_IBAN_LENGTH; break; /* ME -> Montenegro */
      case 1403: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* NC -> Neukaledonien */
      case 1412: if(iban_len!=18)return INVALID_IBAN_LENGTH; break; /* NL -> Niederlande */
      case 1415: if(iban_len!=15)return INVALID_IBAN_LENGTH; break; /* NO -> Norwegen */
      case  120: if(iban_len!=20)return INVALID_IBAN_LENGTH; break; /* AT -> Österreich */
      case 1611: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* PK -> Pakistan */
      case 1619: if(iban_len!=29)return INVALID_IBAN_LENGTH; break; /* PS -> Palästinensische Autonomiegebiete */
      case 1612: if(iban_len!=28)return INVALID_IBAN_LENGTH; break; /* PL -> Polen */
      case 1620: if(iban_len!=25)return INVALID_IBAN_LENGTH; break; /* PT -> Portugal */
      case 1805: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* RE -> Réunion */
      case 1815: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* RO -> Rumänien */
      case  212: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* BL -> Saint-Barthélemy */
      case 1306: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* MF -> Saint-Martin */
      case 1913: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* SM -> San Marino */
      case 1901: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* SA -> Saudi-Arabien */
      case 1905: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* SE -> Schweden */
      case  308: if(iban_len!=21)return INVALID_IBAN_LENGTH; break; /* CH -> Schweiz */
      case 1819: if(iban_len!=22)return INVALID_IBAN_LENGTH; break; /* RS -> Serbien */
      case 1911: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* SK -> Slowakei */
      case 1909: if(iban_len!=19)return INVALID_IBAN_LENGTH; break; /* SI -> Slowenien */
      case  519: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* ES -> Spanien */
      case 1613: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* PM -> St. Pierre und Miquelon */
      case  326: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* CZ -> Tschechien */
      case 2014: if(iban_len!=24)return INVALID_IBAN_LENGTH; break; /* TN -> Tunesien */
      case 2018: if(iban_len!=26)return INVALID_IBAN_LENGTH; break; /* TR -> Türkei */
      case  821: if(iban_len!=28)return INVALID_IBAN_LENGTH; break; /* HU -> Ungarn */
      case  105: if(iban_len!=23)return INVALID_IBAN_LENGTH; break; /* AE -> Vereinigte Arabische Emirate */
      case  702: if(iban_len!=22)return INVALID_IBAN_LENGTH; break; /* GB -> Vereinigtes Königreich */
      case 2306: if(iban_len!=27)return INVALID_IBAN_LENGTH; break; /* WF -> Wallis und Futuna */
      case  325: if(iban_len!=28)return INVALID_IBAN_LENGTH; break; /* CY -> Zypern */
      default: break;   /* unbekannt, stehen lassen */
   }

      /* BBAN (Basic Bank Account Number) kopieren (alphanumerisch) */
   test=0;
   for(ptr=iban+4,dptr=check;*ptr;ptr++){
      if((c=*ptr)>='0' && c<='9')
         *dptr++=c;
      else if(c>='A' && c<='Z'){
         c+=10-'A';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
      else if(c>='a' && c<='z'){
         c+=10-'a';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
   }

      /* Ländercode (2-stellig/alphabetisch) kopieren */
   ptr=iban;
   if((c=*ptr++)>='A' && c<='Z'){
      c+=10-'A';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   else if(c>='a' && c<='z'){
      c+=10-'a';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   if((c=*ptr++)>='A' && c<='Z'){
      c+=10-'A';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }
   else if(c>='a' && c<='z'){
      c+=10-'a';
      *dptr++=c/10+'0';
      *dptr++=c%10+'0';
   }

      /* Prüfziffer kopieren */
   *dptr++=*ptr++;
   *dptr++=*ptr++;
   *dptr=0;

   for(rest=0,ptr=check;*ptr;){
      zahl=rest/10;
      zahl=zahl*10+rest%10;
      for(j=0;j<6 && *ptr;ptr++,j++)zahl=zahl*10+ *ptr-'0';
      rest=zahl%97;
   }
   zahl=98-rest;
   if(rest==1)test=1;   /* IBAN ok */
   if((*iban=='D' || *iban=='d') && (*(iban+1)=='E' || *(iban+1)=='e')){ /* Konto testen, evl. IBAN gegentesten */
      for(ptr=iban+4,blz2=dptr=check,j=0;j<8 && *ptr;ptr++)if(isdigit(*ptr)){
         *dptr++=*ptr;
         j++;
      }
      *dptr++=0;
      for(kto2=dptr,j=0;j<10 && *ptr;ptr++)if(isdigit(*ptr)){
         *dptr++=*ptr;
         j++;
      }
      *dptr=0;
      if((ret=ret_kc=kto_check_blz(blz2,kto2))>0)test|=2;
      if(retval)*retval=ret;

      if(test&1){
            /* Überprüfung bis hierhin ok, nun Unterkonto und IBAN-Regeln testen
             *
             * Prüfziffermethode und IBAN-Regel auf dem kleinen Dienstweg holen
             * (es müssen nicht alle Tests doppelt und dreifach gemacht werden ;-)
             * Dann testen, ob eine selbst generierte IBAN (mit Regeln und
             * Unterkonto-Ersetzung) mit der übergebenen Variante übereinstimmt,
             * falls nicht, Fehlermeldung/Warnung.
             */
         j=lut_index(blz2);
         if(j>0){
            if((ret=iban_init())<OK)return ret;  /* alle notwendigen Blocks kontrollieren, evl. nachladen */
            uk=uk_pz_methoden[pz_methoden[j]];
            nachfolge=nachfolge_blz[startidx[j]];

            if(iban_regel)
               regel=iban_regel[startidx[j]];
            else
               regel=0;
            if(uk || nachfolge || regel){
               papier2=iban_bic_gen(blz2,kto2,NULL,NULL,NULL,&ret);
               if(ret==NO_IBAN_CALCULATION)return IBAN_CHKSUM_OK_NO_IBAN_CALCULATION;
               if(ret==OK_IBAN_WITHOUT_KC_TEST || ret==OK_KTO_REPLACED_NO_PZ)test=4; /* kein Test der Bankverbindung */
               if(papier2){
                  for(ptr=papier2,dptr=iban2;*ptr;ptr++)if(*ptr!=' ')*dptr++=*ptr;
                  *dptr=0;
                  FREE(papier2);
                  if(strcasecmp(iban,iban2)){
                     if(regel>0){
#if EXTRA_BLZ_REGEL
                        if(!strcmp(iban+12,iban2+12)) /* nur BLZ geändert */
                           return IBAN_CHKSUM_OK_RULE_IGNORED_BLZ;
                        else
#endif
                           return IBAN_CHKSUM_OK_RULE_IGNORED;
                     }
                     else if(nachfolge)
                        return IBAN_CHKSUM_OK_NACHFOLGE_BLZ_DEFINED;
                     else  /*  bei Regel==0 kann nur ein Unterkonto fehlen */
                        return IBAN_CHKSUM_OK_UNTERKTO_MISSING;
                  }
               }
            }
         }
      }
   }
   else{
      if(test)test|=2;  /* falls IBAN nicht ok ist, test auf 0 lassen */
      if(retval)*retval=NO_GERMAN_BIC;
   }
   switch(test){
      case 1: 
         if(ret_kc==INVALID_BLZ)
            return IBAN_CHKSUM_OK_BLZ_INVALID;
         else if(ret_kc==LUT2_NOT_INITIALIZED)
            return IBAN_CHKSUM_OK_KC_NOT_INITIALIZED;
         else
            return IBAN_OK_KTO_NOT;
      case 2: return KTO_OK_IBAN_NOT;
      case 3: return OK;
      case 4: if(retval)*retval=OK_NO_CHK; return OK_IBAN_WITHOUT_KC_TEST;
      default: return FALSE;
   }
}

/* Funktion ipi_gen() +§§§1 */
/* ###########################################################################
 * # Die Funktion ipi_gen generiert einen Strukturierten Verwendungszweck    #
 * # für eine IPI (International Payment Instruction). Der Zweck darf nur    #
 * # Buchstaben und Zahlen enthalten; Buchstaben werden dabei in Großbuch-   #
 * # staben umgewandelt. Andere Zeichen sind hier nicht zulässig. Der        #
 * # Verwendungszweck wird links mit Nullen bis auf 18 Byte aufgefüllt, dann #
 * # die Prüfsumme berechnet und eingesetzt.                                 #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    zweck:      Zweck (maximal 18 Byte)                                  #
 * #    dst:        Adresse eines Speicherbereichs mit mindestens 21 Byte,   #
 * #                in die der generierte Verwendungszweck (mit Prüfsumme)   #
 * #                geschrieben wird, oder NULL (falls nicht benötigt)       #
 * #   papier:      Adresse eines Speicherbereichs mit mindestens 26 Byte,   #
 * #                in die die Papierform des Verwendungszwecks (mit Leer-   #
 * #                zeichen nach jeweils 5 Zeichen) geschrieben wird, oder   #
 * #                NULL (falls nicht benötigt)                              #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int ipi_gen(char *zweck,char *dst,char *papier)
{
   char c,check[64],buffer[24],*ptr,*dptr;
   int i;
   UINT4 zahl,rest;

   if(dst)*dst=0;
   if(papier)*papier=0;
   if(strlen(zweck)>18)return IPI_INVALID_LENGTH;

      /* der Verwendungszweck wird nun nach dst kopiert und linksbündig mit
       * Nullen aufgefüllt.
       */
      /* ptr auf Ende des Verwendungszwecks setzen, Zeichen testen */
   for(ptr=zweck;*ptr;ptr++)if((c=*ptr) && !(isdigit(c) || (c>='A' && c<='Z') || (c>='a' && c<='z')))return IPI_INVALID_CHARACTER;
   for(dptr=buffer+20;ptr>=zweck;*dptr--=toupper(*ptr--));
   while(dptr>buffer)*dptr--='0';

      /* Verwendungszweck nach check kopieren, dabei Buchstaben konvertieren */
   for(ptr=buffer+2,dptr=check;*ptr;ptr++){
      if((c=*ptr)>='0' && c<='9')
         *dptr++=c;
      else if(c>='A' && c<='Z'){
         c+=10-'A';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
      else if(c>='a' && c<='z'){
         c+=10-'a';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
   }

      /* Prüfziffer kopieren */
   *dptr++='0';
   *dptr++='0';
   *dptr++=0;

   for(rest=0,ptr=check;*ptr;){
      zahl=rest;
      for(i=0;i<6 && *ptr;ptr++,i++)zahl=zahl*10+ *ptr-'0'; /* maximal sieben weitere Stellen dazu */
      rest=zahl%97;
   }
   zahl=98-rest;

      /* Prüfziffer schreiben */
   *buffer=zahl/10+'0';
   *(buffer+1)=zahl%10+'0';
   if(dst)for(ptr=buffer,dptr=dst;(*dptr++=*ptr++););
   if(papier)for(ptr=buffer,dptr=papier,i=1;(*dptr++=*ptr++);)if(i<20 && !(i++%4))*dptr++=' ';
   return OK;
}

/* Funktion ipi_gen_id() +§§§1 */
/* ###########################################################################
 * # Die Funktion ipi_gen_id entspricht der Funktion ipi_gen(); allerdings   #
 * # wird für die beiden Parameter dst und papier Speicher allokiert und     #
 * # über jeweils ein Handle wieder zurückgegeben. Mit der Funktion          #
 * # kc_id2ptr() kann das Handle in einen String umgewandelt werden, sowie   #
 * # mittels der Funktion kc_id_free() wieder freigegeben werden.            #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int ipi_gen_id(char *zweck,int *dst,int *papier)
{
   char *d,*p;
   int retval,rv;

   if(!(d=(char*)malloc(24)))return ERROR_MALLOC;
   if(!(p=(char*)malloc(32))){
      free(d);
      return ERROR_MALLOC;
   }
   retval=ipi_gen(zweck,d,p);
   if((rv=kc_ptr2id(d,dst,1)<0) || (rv=kc_ptr2id(p,papier,1)<0))return rv;
   return retval;
}

/* Funktion ipi_check() +§§§1 */
/* ###########################################################################
 * # Die Funktion ipi_check testet einen Strukturierten Verwendungszweck     #
 * # für eine IPI (International Payment Instruction). Der Zweck darf nur    #
 * # Buchstaben und Zahlen enthalten und muß genau 20 Byte lang sein, wobei  #
 * # eingestreute Blanks oder Tabs ignoriert werden.                         #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    zweck: der Strukturierte Verwendungszweck, der getestet werden soll  #
 * #                                                                         #
 * # Copyright (C) 2008 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int ipi_check(char *zweck)
{
   char c,zweck1[64],check[64],*ptr,*dptr;
   int j;
   UINT4 zahl,rest;

      /* Blanks und Tabs eliminieren */
   for(ptr=zweck,dptr=zweck1;*ptr;ptr++)if(*ptr!=' ' && *ptr!='\t')*dptr++=*ptr;
   *dptr=0;

      /* Verwendungszweck nach check kopieren, dabei Buchstaben konvertieren */
   if(strlen(zweck1)!=20)return IPI_CHECK_INVALID_LENGTH;
   for(ptr=zweck1+2,dptr=check;*ptr;ptr++){
      if((c=*ptr)>='0' && c<='9')
         *dptr++=c;
      else if(c>='A' && c<='Z'){
         c+=10-'A';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
      else if(c>='a' && c<='z'){
         c+=10-'a';
         *dptr++=c/10+'0';
         *dptr++=c%10+'0';
      }
   }

      /* Prüfziffer kopieren */
   *dptr++=*zweck;
   *dptr++=*(zweck+1);
   *dptr++=0;

   for(rest=0,ptr=check;*ptr;){
      zahl=rest;
      for(j=0;j<6 && *ptr;ptr++,j++)zahl=zahl*10+ *ptr-'0'; /* maximal sieben weitere Stellen dazu */
      rest=zahl%97;
   }
   if(rest==1)
      return OK;
   else
      return FALSE;
}

/* Hilfsfunktionen für die Suche nach Bankleitzahlen +§§§1 */
/* Überblick +§§§2 */
/* ###########################################################################
 * # Diese Funktionen dienen zum Suchen nach Bankleitzahlen über die anderen #
 * # Felder der LUT-Datei, z.B. Banken in einem bestimmten Ort oder mit      #
 * # einem bestimmten Namen etc.                                             #
 * #                                                                         #
 * # Copyright (C) 2009,2011 Michael Plugge <m.plugge@hs-mannheim.de>        #
 * ###########################################################################
 */

/* Funktion volltext_zeichen() +§§§2 */
/* Diese Funktion gibt für Zeichen die bei der Volltextsuche gültig sind
 * (Buchstaben, Zahlen und Umlaute) 1 zurück, für alle anderen Zeichen 0. Der
 * Parameter wird als char **c übergeben, damit er bei UTF-8-Zeichen oder
 * HTML-Entities auf den Buchstaben vor dem Ende des Zeichens inkrementiert
 * werden kann und so eine saubere Erkennung der Zeichen möglich ist.
 */
static int volltext_zeichen(unsigned char **c)
{
   unsigned char *p;

   switch(**c){

         /* Kleinbuchstaben */
      case 'a': return 1;
      case 'b': return 1;
      case 'c': return 1;
      case 'd': return 1;
      case 'e': return 1;
      case 'f': return 1;
      case 'g': return 1;
      case 'h': return 1;
      case 'i': return 1;
      case 'j': return 1;
      case 'k': return 1;
      case 'l': return 1;
      case 'm': return 1;
      case 'n': return 1;
      case 'o': return 1;
      case 'p': return 1;
      case 'q': return 1;
      case 'r': return 1;
      case 's': return 1;
      case 't': return 1;
      case 'u': return 1;
      case 'v': return 1;
      case 'w': return 1;
      case 'x': return 1;
      case 'y': return 1;
      case 'z': return 1;

         /* Großbuchstaben: */
      case 'A': return 1;
      case 'B': return 1;
      case 'C': return 1;
      case 'D': return 1;
      case 'E': return 1;
      case 'F': return 1;
      case 'G': return 1;
      case 'H': return 1;
      case 'I': return 1;
      case 'J': return 1;
      case 'K': return 1;
      case 'L': return 1;
      case 'M': return 1;
      case 'N': return 1;
      case 'O': return 1;
      case 'P': return 1;
      case 'Q': return 1;
      case 'R': return 1;
      case 'S': return 1;
      case 'T': return 1;
      case 'U': return 1;
      case 'V': return 1;
      case 'W': return 1;
      case 'X': return 1;
      case 'Y': return 1;
      case 'Z': return 1;

         /* Zahlen */
      case '0': return 1;
      case '1': return 1;
      case '2': return 1;
      case '3': return 1;
      case '4': return 1;
      case '5': return 1;
      case '6': return 1;
      case '7': return 1;
      case '8': return 1;
      case '9': return 1;

         /* HTML-Entities */
      case '&': 
           /* testen auf einige HTML Entities. Die folgenden Entities werden behandelt:
            *    &.uml;
            *    &.acute;
            *    &.grave;
            *    &.tilde;
            *    &.circ;
            *    &szlig;
            *    &quot;
            *    &amp;
            *    &lt;
            *    &gt;
            *    &#xxx; der Umlaute und Akzentbuchstaben (numerisch)
            *
            * Bei den Umlauten und Akzenten wird der erste Buchstabe hier nicht getestet,
            * sondern erst später in der eigentlichen Suche. Es würde den Code verkomplizieren,
            * ohne eigentlichen Nutzen zu bringen (der Test wird später doch durchgeführt).
            */
           p=*c+2; if(*p++=='u' && *p++=='m' && *p++=='l' && *p++==';')                          {*c+=5; return 1;}
           p=*c+2; if(*p++=='a' && *p++=='c' && *p++=='u' && *p++=='t' && *p++=='e' && *p++==';'){*c+=7; return 1;}
           p=*c+2; if(*p++=='g' && *p++=='r' && *p++=='a' && *p++=='v' && *p++=='e' && *p++==';'){*c+=7; return 1;}
           p=*c+2; if(*p++=='t' && *p++=='i' && *p++=='l' && *p++=='d' && *p++=='e' && *p++==';'){*c+=7; return 1;}
           p=*c+2; if(*p++=='c' && *p++=='i' && *p++=='r' && *p++=='c' && *p++==';')             {*c+=6; return 1;}
           p=*c+1; if(*p++=='s' && *p++=='z' && *p++=='l' && *p++=='i' && *p++=='g' && *p++==';'){*c+=7; return 1;}
           p=*c+1; if(*p++=='q' && *p++=='u' && *p++=='o' && *p++=='t' && *p++==';')             {*c+=5; return 1;}
           p=*c+1; if(*p++=='a' && *p++=='m' && *p++=='p' && *p++==';')                          {*c+=4; return 1;}
           p=*c+1; if(*p++=='l' && *p++=='t' && *p++==';')                                       {*c+=3; return 1;}
           p=*c+1; if(*p++=='g' && *p++=='t' && *p++==';')                                       {*c+=3; return 1;}

               /* numerische Escape-Sequenzen (hier einfach sortiert, ohne Buchstabenwerte) */
           p=*c+1;
           if(*p=='#' && *(p+4)==';')switch(atoi((char*)p+1)){
              case 192:
              case 193:
              case 194:
              case 195:
              case 196:
              case 200:
              case 201:
              case 202:
              case 203:
              case 204:
              case 205:
              case 206:
              case 207:
              case 209:
              case 210:
              case 211:
              case 212:
              case 213:
              case 214:
              case 217:
              case 218:
              case 219:
              case 220:
              case 221:
              case 223:
              case 224:
              case 225:
              case 226:
              case 227:
              case 228:
              case 232:
              case 233:
              case 234:
              case 235:
              case 236:
              case 237:
              case 238:
              case 239:
              case 241:
              case 242:
              case 243:
              case 244:
              case 245:
              case 246:
              case 249:
              case 250:
              case 251:
              case 252:
              case 253:
              case 255:
                 *c+=5;
                 return 1;
              default:
                 return 0;
           }
           return 0;    /* alles was mit & beginnt und noch nicht gefunden wurde verwerfen */

         /* ISO 8859-1 Umlaute etc. */
      case 0xc1: return 1;    /* ISO-8859-1: A acute */
      case 0xc2: return 1;    /* ISO-8859-1: A circ  */
      case 0xc0: return 1;    /* ISO-8859-1: A grave */
      case 0xc4: return 1;    /* ISO-8859-1: A uml   */
      case 0xe8: return 1;    /* ISO-8859-1: e grave */
      case 0xc9: return 1;    /* ISO-8859-1: E acute */
      case 0xca: return 1;    /* ISO-8859-1: E circ  */
      case 0xc8: return 1;    /* ISO-8859-1: E grave */
      case 0xcb: return 1;    /* ISO-8859-1: E uml   */
      case 0xee: return 1;    /* ISO-8859-1: i circ  */
      case 0xef: return 1;    /* ISO-8859-1: i uml   */
      case 0xcd: return 1;    /* ISO-8859-1: I acute */
      case 0xce: return 1;    /* ISO-8859-1: I circ  */
      case 0xcc: return 1;    /* ISO-8859-1: I grave */
      case 0xcf: return 1;    /* ISO-8859-1: I uml   */
      case 0xf1: return 1;    /* ISO-8859-1: n tilde */
      case 0xd1: return 1;    /* ISO-8859-1: N tilde */
      case 0xf3: return 1;    /* ISO-8859-1: o acute */
      case 0xf4: return 1;    /* ISO-8859-1: o circ  */
      case 0xf2: return 1;    /* ISO-8859-1: o grave */
      case 0xf5: return 1;    /* ISO-8859-1: o tilde */
      case 0xf6: return 1;    /* ISO-8859-1: o uml   */
      case 0xd5: return 1;    /* ISO-8859-1: O tilde */
      case 0xfa: return 1;    /* ISO-8859-1: u acute */
      case 0xfb: return 1;    /* ISO-8859-1: u circ  */
      case 0xf9: return 1;    /* ISO-8859-1: u grave */
      case 0xfc: return 1;    /* ISO-8859-1: u uml   */
      case 0xda: return 1;    /* ISO-8859-1: U acute */
      case 0xdb: return 1;    /* ISO-8859-1: U circ  */
      case 0xd9: return 1;    /* ISO-8859-1: U grave */
      case 0xdc: return 1;    /* ISO-8859-1: U uml   */
      case 0xfd: return 1;    /* ISO-8859-1: Y acute */
      case 0xdd: return 1;    /* ISO-8859-1: Y acute */
      case 0xff: return 1;    /* ISO-8859-1: y uml   */
      case 0xdf: return 1;    /* ISO-8859-1: s szlig */
      case 0xd2: return 1;    /* ISO-8859-1: O grave */
      case 0xd4: return 1;    /* ISO-8859-1: O circ  */
      case 0xd3: return 1;    /* ISO-8859-1: O acute */
      case 0xd6: return 1;    /* ISO-8859-1: O uml   */
      case 0xe4: return 1;    /* ISO-8859-1: a uml   */
      case 0xe0: return 1;    /* ISO-8859-1: a grave */
      case 0xe2: return 1;    /* ISO-8859-1: a circ  */
      case 0xe3: return 1;    /* ISO-8859-1: a tilde */
      case 0xe9: return 1;    /* ISO-8859-1: e acute */
      case 0xea: return 1;    /* ISO-8859-1: e circ  */
      case 0xeb: return 1;    /* ISO-8859-1: e uml   */
      case 0xec: return 1;    /* ISO-8859-1: i grave */
      case 0xed: return 1;    /* ISO-8859-1: i acute */
      case 0xe1: return 1;    /* ISO-8859-1: a acute */

      case 0xc3:  /* UTF-8 Zeichen */
         switch(*(*c+1)){
               /* UTF8-Kodierung (immer mit Präfix 0xc3): */
            case 0xa1:     /* UTF-8:  a acute  */
            case 0xa2:     /* UTF-8:  a circ   */
            case 0xa0:     /* UTF-8:  a grave  */
            case 0xa3:     /* UTF-8:  a tilde  */
            case 0xa4:     /* UTF-8:  a uml    */
            case 0X81:     /* UTF-8:  A acute  */
            case 0X82:     /* UTF-8:  A circ   */
            case 0X80:     /* UTF-8:  A grave  */
            case 0X83:     /* UTF-8:  A tilde  */
            case 0X84:     /* UTF-8:  A uml    */
            case 0xa9:     /* UTF-8:  e acute  */
            case 0xaa:     /* UTF-8:  e circ   */
            case 0xa8:     /* UTF-8:  e grave  */
            case 0xab:     /* UTF-8:  e uml    */
            case 0x89:     /* UTF-8:  E acute  */
            case 0x8a:     /* UTF-8:  E circ   */
            case 0x88:     /* UTF-8:  E grave  */
            case 0x8b:     /* UTF-8:  E uml    */
            case 0xad:     /* UTF-8:  i acute  */
            case 0xae:     /* UTF-8:  i circ   */
            case 0xac:     /* UTF-8:  i grave  */
            case 0xaf:     /* UTF-8:  i uml    */
            case 0x8d:     /* UTF-8:  I acute  */
            case 0x8e:     /* UTF-8:  I circ   */
            case 0x8c:     /* UTF-8:  I grave  */
            case 0x8f:     /* UTF-8:  I uml    */
            case 0xb1:     /* UTF-8:  n tilde  */
            case 0x91:     /* UTF-8:  N tilde  */
            case 0xb3:     /* UTF-8:  o acute  */
            case 0xb4:     /* UTF-8:  o circ   */
            case 0xb2:     /* UTF-8:  o grave  */
            case 0xb5:     /* UTF-8:  o tilde  */
            case 0xb6:     /* UTF-8:  o uml    */
            case 0x93:     /* UTF-8:  O acute  */
            case 0x94:     /* UTF-8:  O circ   */
            case 0x92:     /* UTF-8:  O grave  */
            case 0x95:     /* UTF-8:  O tilde  */
            case 0x96:     /* UTF-8:  O uml    */
            case 0xba:     /* UTF-8:  u acute  */
            case 0xbb:     /* UTF-8:  u circ   */
            case 0xb9:     /* UTF-8:  u grave  */
            case 0xbc:     /* UTF-8:  u uml    */
            case 0x9a:     /* UTF-8:  U acute  */
            case 0x9b:     /* UTF-8:  U circ   */
            case 0x99:     /* UTF-8:  U grave  */
            case 0x9c:     /* UTF-8:  U uml    */
            case 0xbd:     /* UTF-8:  y acute  */
            case 0x9d:     /* UTF-8:  Y acute  */
            case 0xbf:     /* UTF-8:  y uml    */
            case 0x9f:     /* UTF-8:  szlig    */
               (*c)++;     /* Der Pointer muß inkrementiert werden (2-Byte-Zeichen) */
               return 1;
            default:
               return 0;
         }

            /* CP-850, ohne Kollisionen mit ISO 8859-1 */
      case 0xa0: return 1;    /* CP-850: a acute */
      case 0x83: return 1;    /* CP-850: a circ  */
      case 0x85: return 1;    /* CP-850: a grave */
      case 0xc6: return 1;    /* CP-850: a tilde */
      case 0x84: return 1;    /* CP-850: a uml   */
      case 0xb5: return 1;    /* CP-850: A acute */
      case 0xb6: return 1;    /* CP-850: A circ  */
      case 0xb7: return 1;    /* CP-850: A grave */
      case 0xc7: return 1;    /* CP-850: A tilde */
      case 0x8e: return 1;    /* CP-850: A uml   */
      case 0x82: return 1;    /* CP-850: e acute */
      case 0x88: return 1;    /* CP-850: e circ  */
      case 0x8a: return 1;    /* CP-850: e grave */
      case 0x89: return 1;    /* CP-850: e uml   */
      case 0x90: return 1;    /* CP-850: E acute */
      case 0xa1: return 1;    /* CP-850: i acute */
      case 0x8c: return 1;    /* CP-850: i circ  */
      case 0x8d: return 1;    /* CP-850: i grave */
      case 0x8b: return 1;    /* CP-850: i uml   */
      case 0xd7: return 1;    /* CP-850: I circ  */
      case 0xde: return 1;    /* CP-850: I grave */
      case 0xd8: return 1;    /* CP-850: I uml   */
      case 0xa4: return 1;    /* CP-850: n tilde */
      case 0xa5: return 1;    /* CP-850: N tilde */
      case 0xa2: return 1;    /* CP-850: o acute */
      case 0x93: return 1;    /* CP-850: o circ  */
      case 0x95: return 1;    /* CP-850: o grave */
      case 0x94: return 1;    /* CP-850: o uml   */
      case 0xe5: return 1;    /* CP-850: O tilde */
      case 0x99: return 1;    /* CP-850: O uml   */
      case 0xa3: return 1;    /* CP-850: u acute */
      case 0x96: return 1;    /* CP-850: u circ  */
      case 0x97: return 1;    /* CP-850: u grave */
      case 0x81: return 1;    /* CP-850: u uml   */
      case 0x9a: return 1;    /* CP-850: U uml   */
      case 0x98: return 1;    /* CP-850: y uml   */

      default: /* alle sonstigen Zeichen verwerfen */
         return 0;
   }
}

/* Funktion get_sortc() +§§§2 */
   /* Diese Funktion holt einen "Buchstaben" aus einem String und gibt eine auf
    * 12 Bit erweiterte Form zurück, bei denen Groß- und Kleinbuchstaben als
    * gleich angesehen werden und akzentuierte Buchstaben nach den
    * Grundbuchstaben eingereiht werden (allerdings von diesen unterschieden
    * werden, anders als bis Version 3.6 von konto_check). Für UTF-8 sowie
    * HTML-kodierte Zeichenfolgen werden die entsprechenden Sequenzen ebenfalls
    * erkannt und der Eingangspointer dann entsprechend inkrementiert zurückgegeben
    * (er steht auf dem Beginn des nächsten "Buchstabens")
    */
static int get_sortc(char **a,int enc)
{
   unsigned char *p,*ptr;
   int base,accent;

   ptr=(unsigned char*)*a;
   accent=0;
   switch(base=*ptr++){

         /* Großbuchstaben: */
      case 'A': base='a'; break;
      case 'B': base='b'; break;
      case 'C': base='c'; break;
      case 'D': base='d'; break;
      case 'E': base='e'; break;
      case 'F': base='f'; break;
      case 'G': base='g'; break;
      case 'H': base='h'; break;
      case 'I': base='i'; break;
      case 'J': base='j'; break;
      case 'K': base='k'; break;
      case 'L': base='l'; break;
      case 'M': base='m'; break;
      case 'N': base='n'; break;
      case 'O': base='o'; break;
      case 'P': base='p'; break;
      case 'Q': base='q'; break;
      case 'R': base='r'; break;
      case 'S': base='s'; break;
      case 'T': base='t'; break;
      case 'U': base='u'; break;
      case 'V': base='v'; break;
      case 'W': base='w'; break;
      case 'X': base='x'; break;
      case 'Y': base='y'; break;
      case 'Z': base='z'; break;

                /* DOS CP-850 und Kollisionen mit ISO-8859-1 */
      case 0xa0: base='a'; accent=1; break;    /* CP-850:  a acute */
      case 0x83: base='a'; accent=2; break;    /* CP-850:  a circ  */
      case 0x85: base='a'; accent=3; break;    /* CP-850:  a grave */
      case 0xc6: base='a'; accent=4; break;    /* CP-850:  a tilde */
      case 0x84: base='a'; accent=5; break;    /* CP-850:  a uml   */
      case 0xb5: base='a'; accent=1; break;    /* CP-850:  A acute */
      case 0xb6: base='a'; accent=2; break;    /* CP-850:  A circ  */
      case 0xb7: base='a'; accent=3; break;    /* CP-850:  A grave */
      case 0xc7: base='a'; accent=4; break;    /* CP-850:  A tilde */
      case 0x8e: base='a'; accent=5; break;    /* CP-850:  A uml   */
      case 0x82: base='e'; accent=1; break;    /* CP-850:  e acute */
      case 0x88: base='e'; accent=2; break;    /* CP-850:  e circ  */
      case 0x8a: base='e'; accent=3; break;    /* CP-850:  e grave */
      case 0x89: base='e'; accent=5; break;    /* CP-850:  e uml   */
      case 0x90: base='e'; accent=1; break;    /* CP-850:  E acute */
      case 0xd2:
         if(enc==4){
            base='e'; accent=2; break;         /* CP-850:  E circ  */
         }
         else{
            base='o'; accent=3; break;         /* ISO-8859-1: O grave */
         }
      case 0xd4:
         if(enc==4){
            base='e'; accent=3; break;         /* CP-850: E grave */
         }
         else{
            base='o'; accent=2; break;         /* ISO-8859-1: O circ  */
         }
      case 0xd3:
         if(enc==4){
            base='e'; accent=5; break;         /* CP-850: E uml   */
         }
         else{
            base='o'; accent=1; break;         /* ISO-8859-1: O acute */
         }
      case 0xa1: base='i'; accent=1; break;    /* CP-850: i acute */
      case 0x8c: base='i'; accent=2; break;    /* CP-850: i circ  */
      case 0x8d: base='i'; accent=3; break;    /* CP-850: i grave */
      case 0x8b: base='i'; accent=5; break;    /* CP-850: i uml   */
      case 0xd6:
         if(enc==4){
            base='i'; accent=1; break;         /* CP-850: I acute */
         }
         else{
            base='o'; accent=5; break;         /* ISO-8859-1: O uml   */
         }
      case 0xd7: base='i'; accent=2; break;    /* CP-850: I circ  */
      case 0xde: base='i'; accent=3; break;    /* CP-850: I grave */
      case 0xd8: base='i'; accent=5; break;    /* CP-850: I uml   */
      case 0xa4: base='n'; accent=4; break;    /* CP-850: n tilde */
      case 0xa5: base='n'; accent=4; break;    /* CP-850: N tilde */
      case 0xa2: base='o'; accent=1; break;    /* CP-850: o acute */
      case 0x93: base='o'; accent=2; break;    /* CP-850: o circ  */
      case 0x95: base='o'; accent=3; break;    /* CP-850: o grave */
      case 0xe4:
         if(enc==4){
            base='o'; accent=4; break;         /* CP-850: o tilde */
         }
         else{
            base='a'; accent=5; break;         /* ISO-8859-1: a uml   */
         }
      case 0x94: base='o'; accent=5; break;    /* CP-850: ” uml   */
      case 0xe0:
         if(enc==4){
            base='o'; accent=1; break;         /* CP-850: O acute */
         }
         else{
            base='a'; accent=3; break;         /* ISO-8859-1: a grave */
         }
      case 0xe2:
         if(enc==4){
            base='o'; accent=2; break;         /* CP-850: O circ  */
         }
         else{
            base='a'; accent=2; break;         /* ISO-8859-1: a circ  */
         }
      case 0xe3:
         if(enc==4){
            base='o'; accent=3; break;         /* CP-850: O grave */
         }
         else{
            base='a'; accent=4; break;         /* ISO-8859-1: a tilde */
         }
      case 0xe5: base='o'; accent=4; break;    /* CP-850: O tilde */
      case 0x99: base='o'; accent=5; break;    /* CP-850: O uml   */
      case 0xa3: base='u'; accent=1; break;    /* CP-850: u acute */
      case 0x96: base='u'; accent=2; break;    /* CP-850: u circ  */
      case 0x97: base='u'; accent=3; break;    /* CP-850: u grave */
      case 0x81: base='u'; accent=5; break;    /* CP-850: u uml   */
      case 0xe9:
         if(enc==4){
            base='u'; accent=1; break;         /* CP-850: U acute */
         }
         else{
            base='e'; accent=1; break;         /* ISO-8859-1: e acute */
         }
      case 0xea:
         if(enc==4){
            base='u'; accent=2; break;         /* CP-850: U circ  */
         }
         else{
            base='e'; accent=2; break;         /* ISO-8859-1: e circ  */
         }
      case 0xeb:
         if(enc==4){
            base='u'; accent=3; break;         /* CP-850: U grave */
         }
         else{
            base='e'; accent=5; break;         /* ISO-8859-1: e uml   */
         }
      case 0x9a: base='u'; accent=5; break;    /* CP-850: U uml   */
      case 0xec:
         if(enc==4){
            base='y'; accent=1; break;         /* CP-850: y acute */
         }
         else{
            base='i'; accent=3; break;         /* ISO-8859-1: i grave */
         }
      case 0xed:
         if(enc==4){
            base='y'; accent=1; break;         /* CP-850: Y acute */
         }
         else{
            base='i'; accent=1; break;         /* ISO-8859-1: i acute */
         }
      case 0x98: base='y'; accent=5; break;    /* CP-850: y uml   */
      case 0xe1:
         if(enc==4){
            base='s'; accent=1; break;         /* CP-850: s szlig */
         }
         else{
            base='a'; accent=1; break;         /* ISO-8859-1: a acute */
         }


                 /* ISO-8859-1 */
      case 0xc1: base='a'; accent=1; break;    /* ISO-8859-1: A acute */
      case 0xc2: base='a'; accent=2; break;    /* ISO-8859-1: A circ  */
      case 0xc0: base='a'; accent=3; break;    /* ISO-8859-1: A grave */
      case 0xc4: base='a'; accent=5; break;    /* ISO-8859-1: A uml   */
      case 0xe8: base='e'; accent=3; break;    /* ISO-8859-1: e grave */
      case 0xc9: base='e'; accent=1; break;    /* ISO-8859-1: E acute */
      case 0xca: base='e'; accent=2; break;    /* ISO-8859-1: E circ  */
      case 0xc8: base='e'; accent=3; break;    /* ISO-8859-1: E grave */
      case 0xcb: base='e'; accent=5; break;    /* ISO-8859-1: E uml   */
      case 0xee: base='i'; accent=2; break;    /* ISO-8859-1: i circ  */
      case 0xef: base='i'; accent=5; break;    /* ISO-8859-1: i uml   */
      case 0xcd: base='i'; accent=1; break;    /* ISO-8859-1: I acute */
      case 0xce: base='i'; accent=2; break;    /* ISO-8859-1: I circ  */
      case 0xcc: base='i'; accent=3; break;    /* ISO-8859-1: I grave */
      case 0xcf: base='i'; accent=5; break;    /* ISO-8859-1: I uml   */
      case 0xf1: base='n'; accent=4; break;    /* ISO-8859-1: n tilde */
      case 0xd1: base='n'; accent=4; break;    /* ISO-8859-1: N tilde */
      case 0xf3: base='o'; accent=1; break;    /* ISO-8859-1: o acute */
      case 0xf4: base='o'; accent=2; break;    /* ISO-8859-1: o circ  */
      case 0xf2: base='o'; accent=3; break;    /* ISO-8859-1: o grave */
      case 0xf5: base='o'; accent=4; break;    /* ISO-8859-1: o tilde */
      case 0xf6: base='o'; accent=5; break;    /* ISO-8859-1: o uml   */
      case 0xd5: base='o'; accent=4; break;    /* ISO-8859-1: O tilde */
      case 0xfa: base='u'; accent=1; break;    /* ISO-8859-1: u acute */
      case 0xfb: base='u'; accent=2; break;    /* ISO-8859-1: u circ  */
      case 0xf9: base='u'; accent=3; break;    /* ISO-8859-1: u grave */
      case 0xfc: base='u'; accent=5; break;    /* ISO-8859-1: u uml   */
      case 0xda: base='u'; accent=1; break;    /* ISO-8859-1: U acute */
      case 0xdb: base='u'; accent=2; break;    /* ISO-8859-1: U circ  */
      case 0xd9: base='u'; accent=3; break;    /* ISO-8859-1: U grave */
      case 0xdc: base='u'; accent=5; break;    /* ISO-8859-1: U uml   */
      case 0xfd: base='y'; accent=1; break;    /* ISO-8859-1: Y acute */
      case 0xdd: base='y'; accent=1; break;    /* ISO-8859-1: Y acute */
      case 0xff: base='y'; accent=5; break;    /* ISO-8859-1: y uml   */
      case 0xdf: base='s'; accent=1; break;    /* ISO-8859-1: s szlig */


      case 0xc3:  /* UTF-8 Zeichen */
                 switch(*ptr){

                       /* UTF8-Kodierung (immer mit Präfix 0xc3): */
                    case 0xa1: ptr++; base='a'; accent=1; break;    /* UTF-8: a acute  */
                    case 0xa2: ptr++; base='a'; accent=2; break;    /* UTF-8: a circ   */
                    case 0xa0: ptr++; base='a'; accent=3; break;    /* UTF-8: a grave  */
                    case 0xa3: ptr++; base='a'; accent=4; break;    /* UTF-8: a tilde  */
                    case 0xa4: ptr++; base='a'; accent=5; break;    /* UTF-8: a uml    */
                    case 0X81: ptr++; base='a'; accent=1; break;    /* UTF-8: A acute  */
                    case 0X82: ptr++; base='a'; accent=2; break;    /* UTF-8: A circ   */
                    case 0X80: ptr++; base='a'; accent=3; break;    /* UTF-8: A grave  */
                    case 0X83: ptr++; base='a'; accent=4; break;    /* UTF-8: A tilde  */
                    case 0X84: ptr++; base='a'; accent=5; break;    /* UTF-8: A uml    */
                    case 0xa9: ptr++; base='e'; accent=1; break;    /* UTF-8: e acute  */
                    case 0xaa: ptr++; base='e'; accent=2; break;    /* UTF-8: e circ   */
                    case 0xa8: ptr++; base='e'; accent=3; break;    /* UTF-8: e grave  */
                    case 0xab: ptr++; base='e'; accent=5; break;    /* UTF-8: e uml    */
                    case 0x89: ptr++; base='e'; accent=1; break;    /* UTF-8: E acute  */
                    case 0x8a: ptr++; base='e'; accent=2; break;    /* UTF-8: E circ   */
                    case 0x88: ptr++; base='e'; accent=3; break;    /* UTF-8: E grave  */
                    case 0x8b: ptr++; base='e'; accent=5; break;    /* UTF-8: E uml    */
                    case 0xad: ptr++; base='i'; accent=1; break;    /* UTF-8: i acute  */
                    case 0xae: ptr++; base='i'; accent=2; break;    /* UTF-8: i circ   */
                    case 0xac: ptr++; base='i'; accent=3; break;    /* UTF-8: i grave  */
                    case 0xaf: ptr++; base='i'; accent=5; break;    /* UTF-8: i uml    */
                    case 0x8d: ptr++; base='i'; accent=1; break;    /* UTF-8: I acute  */
                    case 0x8e: ptr++; base='i'; accent=2; break;    /* UTF-8: I circ   */
                    case 0x8c: ptr++; base='i'; accent=3; break;    /* UTF-8: I grave  */
                    case 0x8f: ptr++; base='i'; accent=5; break;    /* UTF-8: I uml    */
                    case 0xb1: ptr++; base='n'; accent=4; break;    /* UTF-8: n tilde  */
                    case 0x91: ptr++; base='n'; accent=4; break;    /* UTF-8: N tilde  */
                    case 0xb3: ptr++; base='o'; accent=1; break;    /* UTF-8: o acute  */
                    case 0xb4: ptr++; base='o'; accent=2; break;    /* UTF-8: o circ   */
                    case 0xb2: ptr++; base='o'; accent=3; break;    /* UTF-8: o grave  */
                    case 0xb5: ptr++; base='o'; accent=4; break;    /* UTF-8: o tilde  */
                    case 0xb6: ptr++; base='o'; accent=5; break;    /* UTF-8: o uml    */
                    case 0x93: ptr++; base='o'; accent=1; break;    /* UTF-8: O acute  */
                    case 0x94: ptr++; base='o'; accent=2; break;    /* UTF-8: O circ   */
                    case 0x92: ptr++; base='o'; accent=3; break;    /* UTF-8: O grave  */
                    case 0x95: ptr++; base='o'; accent=4; break;    /* UTF-8: O tilde  */
                    case 0x96: ptr++; base='o'; accent=5; break;    /* UTF-8: O uml    */
                    case 0xba: ptr++; base='u'; accent=1; break;    /* UTF-8: u acute  */
                    case 0xbb: ptr++; base='u'; accent=2; break;    /* UTF-8: u circ   */
                    case 0xb9: ptr++; base='u'; accent=3; break;    /* UTF-8: u grave  */
                    case 0xbc: ptr++; base='u'; accent=5; break;    /* UTF-8: u uml    */
                    case 0x9a: ptr++; base='u'; accent=1; break;    /* UTF-8: U acute  */
                    case 0x9b: ptr++; base='u'; accent=2; break;    /* UTF-8: U circ   */
                    case 0x99: ptr++; base='u'; accent=3; break;    /* UTF-8: U grave  */
                    case 0x9c: ptr++; base='u'; accent=5; break;    /* UTF-8: U uml    */
                    case 0xbd: ptr++; base='y'; accent=1; break;    /* UTF-8: y acute  */
                    case 0x9d: ptr++; base='y'; accent=1; break;    /* UTF-8: Y acute  */
                    case 0xbf: ptr++; base='y'; accent=5; break;    /* UTF-8: y uml    */
                    case 0x9f: ptr++; base='s'; accent=1; break;    /* UTF-8: szlig    */
                    default:  /* möglicherweise ISO-8859-1 */
                               base='a'; accent=4; break;    /* ISO-8859-1: A tilde */
                 }
                 break;

      case '&':
                 /* testen auf einige HTML Entities. Die folgenden Entities werden behandelt:
                  *    &[aAoOuUiIeEy]uml;
                  *    &[aAoOuUiIeEy]acute;
                  *    &[aAoOuUiIeE]grave;
                  *    &[aAoOuUiIeEn]tilde;
                  *    &[aAoOuUiIeE]circ;
                  *    &szlig;
                  *    &quot;
                  *    &amp;
                  *    &lt;
                  *    &gt;
                  *    &#xxx; der obigen Entities (numerisch)
                  */
                 p=ptr+1; if(*p++=='u' && *p++=='m' && *p++=='l' && *p++==';')                          {base=tolower(*ptr); accent=5; ptr=p; break;}
                 p=ptr+1; if(*p++=='a' && *p++=='c' && *p++=='u' && *p++=='t' && *p++=='e' && *p++==';'){base=tolower(*ptr); accent=1; ptr=p; break;}
                 p=ptr+1; if(*p++=='g' && *p++=='r' && *p++=='a' && *p++=='v' && *p++=='e' && *p++==';'){base=tolower(*ptr); accent=3; ptr=p; break;}
                 p=ptr+1; if(*p++=='t' && *p++=='i' && *p++=='l' && *p++=='d' && *p++=='e' && *p++==';'){base=tolower(*ptr); accent=4; ptr=p; break;}
                 p=ptr+1; if(*p++=='c' && *p++=='i' && *p++=='r' && *p++=='c' && *p++==';')             {base=tolower(*ptr); accent=2; ptr=p; break;}
                 p=ptr+1; if(*ptr=='s' && *p++=='z' && *p++=='l' && *p++=='i' && *p++=='g' && *p++==';'){base='s'; accent=1;  ptr=p; break;}
                 p=ptr;   if(*p++=='q' && *p++=='u' && *p++=='o' && *p++=='t' && *p++==';')             {base='\"';ptr=p; break;}
                 p=ptr;   if(*p++=='a' && *p++=='m' && *p++=='p' && *p++==';')                          {base='&'; ptr=p; break;}
                 p=ptr;   if(*p++=='l' && *p++=='t' && *p++==';')                                       {base='<'; ptr=p; break;}
                 p=ptr;   if(*p++=='g' && *p++=='t' && *p++==';')                                       {base='>'; ptr=p; break;}

                     /* numerische Escape-Sequenzen */
                 p=ptr+1;
                 if(*ptr=='#' && *(p+3)==';'){
                    switch(atoi((char*)p)){
                       case 224: base='a'; accent=3; ptr=p+4; break;
                       case 225: base='a'; accent=1; ptr=p+4; break;
                       case 226: base='a'; accent=2; ptr=p+4; break;
                       case 227: base='a'; accent=4; ptr=p+4; break;
                       case 228: base='a'; accent=5; ptr=p+4; break;
                       case 192: base='a'; accent=3; ptr=p+4; break;
                       case 193: base='a'; accent=1; ptr=p+4; break;
                       case 194: base='a'; accent=2; ptr=p+4; break;
                       case 195: base='a'; accent=4; ptr=p+4; break;
                       case 196: base='a'; accent=5; ptr=p+4; break;
                       case 232: base='e'; accent=3; ptr=p+4; break;
                       case 233: base='e'; accent=1; ptr=p+4; break;
                       case 234: base='e'; accent=2; ptr=p+4; break;
                       case 235: base='e'; accent=5; ptr=p+4; break;
                       case 200: base='e'; accent=3; ptr=p+4; break;
                       case 201: base='e'; accent=1; ptr=p+4; break;
                       case 202: base='e'; accent=2; ptr=p+4; break;
                       case 203: base='e'; accent=5; ptr=p+4; break;
                       case 236: base='i'; accent=3; ptr=p+4; break;
                       case 237: base='i'; accent=1; ptr=p+4; break;
                       case 238: base='i'; accent=2; ptr=p+4; break;
                       case 239: base='i'; accent=5; ptr=p+4; break;
                       case 204: base='i'; accent=3; ptr=p+4; break;
                       case 205: base='i'; accent=1; ptr=p+4; break;
                       case 206: base='i'; accent=2; ptr=p+4; break;
                       case 207: base='i'; accent=5; ptr=p+4; break;
                       case 209: base='n'; accent=4; ptr=p+4; break;
                       case 241: base='n'; accent=4; ptr=p+4; break;
                       case 242: base='o'; accent=3; ptr=p+4; break;
                       case 243: base='o'; accent=1; ptr=p+4; break;
                       case 244: base='o'; accent=2; ptr=p+4; break;
                       case 245: base='o'; accent=4; ptr=p+4; break;
                       case 246: base='o'; accent=5; ptr=p+4; break;
                       case 210: base='o'; accent=3; ptr=p+4; break;
                       case 211: base='o'; accent=1; ptr=p+4; break;
                       case 212: base='o'; accent=2; ptr=p+4; break;
                       case 213: base='o'; accent=4; ptr=p+4; break;
                       case 214: base='o'; accent=5; ptr=p+4; break;
                       case 249: base='u'; accent=3; ptr=p+4; break;
                       case 250: base='u'; accent=1; ptr=p+4; break;
                       case 251: base='u'; accent=2; ptr=p+4; break;
                       case 252: base='u'; accent=5; ptr=p+4; break;
                       case 217: base='u'; accent=3; ptr=p+4; break;
                       case 218: base='u'; accent=1; ptr=p+4; break;
                       case 219: base='u'; accent=2; ptr=p+4; break;
                       case 220: base='u'; accent=5; ptr=p+4; break;
                       case 223: base='s'; accent=1; ptr=p+4; break;
                       case 221: base='y'; accent=1; ptr=p+4; break;
                       case 253: base='y'; accent=1; ptr=p+4; break;
                       case 255: base='y'; accent=5; ptr=p+4; break;
                       default: break;
                    }
                    break;
                 }
                 if(*ptr=='#' && *(p+2)==';'){
                    switch(atoi((char*)p)){
                       case 34: base='\"'; ptr=p+3; break;
                       case 38: base='&'; ptr=p+3; break;
                       case 60: base='<'; ptr=p+3; break;
                       case 62: base='>'; ptr=p+3; break;
                    }
                    break;
                 }
                 break;   /* keine bekannte Escapesequenz gefunden; weitermachen */

      default: break;   /* sonstiges Zeichen, direkt verarbeiten */
   }
   *a=(char*)ptr;
   return base*16+accent;
}

/* Funktion stri_cmp() +§§§3 */
   /* diese Funktion ähnelt wie strcasecmp(): strcmp ohne Groß/Kleinschreibung,
    * dazu werden noch die Umlaute berücksichtigt (diese werden bei den
    * entsprechenden Grundbuchstaben einsortiert). Die Umlaute werden in der
    * Funktion get_sortc() behandelt. Seit der Version 4.0 werden alle
    * Kodierungen (inklusive UTF-8 und HTML Entities) berücksichtigt; vorher
    * war die Behandlung der Umlaute auf ISO-8859-1 beschränkt).
    */
static int stri_cmp(char *a,char *b)
{
   int ac,bc,enc;

   ac=bc=0;
   enc=current_encoding%10;
   while((ac=get_sortc(&a,enc))==(bc=get_sortc(&b,enc)) && ac);
   return ac-bc;
}

/* Funktion strni_cmp() +§§§3 */
  /* Diese Funktion entspricht weitgehend der vorhergehenden (stri_cmp());
   * falls der String a kürzer ist als b und soweit mit b übereinstimmt, wird
   * allerdings "gleich" (0) zurückgegeben. Diese Funktion wird zum Vergleich
   * bei der Suche nach Orten oder Banknamen benutzt.
   */
static int strni_cmp(char *a,char *b)
{
   int ac,bc,enc;

   ac=bc=0;
   enc=current_encoding%10;
   while((ac=get_sortc(&a,enc))==(bc=get_sortc(&b,enc)) && ac);
   if(ac)
      return ac-bc;
   else
      return 0;
}

/* Funktion binary_search_int() +§§§3 */
static int binary_search_int(int a1,int a2,int *base,int *sort_a,int cnt,int *unten,int *anzahl)
{
   int x,y,l,r;

   for(l=0,r=cnt-1,x=(l+r)/2; (a1>(y=base[sort_a[x]]) || a2<y) && l<r;){
      if(a1<y)
         r=x-1;
      else
         l=x+1;
      x=(l+r)/2;
   }
   if(a1>y || a2<y){
      *unten=*anzahl=0;
      return KEY_NOT_FOUND;
   }

   for(l=x;l>=0 && a1<=base[sort_a[l]];l--);
   l++;
   *unten=l;

   for(r=x;r<cnt && a2>=base[sort_a[r]];r++);
   r--;
   *anzahl=r-l+1;
   return OK;
}

/* Funktion binary_search() +§§§3 */
static int binary_search(char *a,char **base,int *sort_a,int cnt,int *unten,int *anzahl)
{
   int x,y,l,r;
   int (*fkt)(char*,char*);

   while(isspace(*a))a++;
   if(*a=='!'){   /* bei Suchaufrufen mit ! als erstem Zeichen -> genaue Suche starten */
      a++;
      fkt=stri_cmp;
   }
   else
      fkt=strni_cmp;

   for(l=0,r=cnt-1,x=(l+r)/2;(y=(*fkt)(a,base[sort_a[x]])) && y && l<r;){
      if(y<0)
         r=x-1;
      else
         l=x+1;
      x=(l+r)/2;
   }
   if(y){
      *unten=*anzahl=0;
      return KEY_NOT_FOUND;
   }

   for(l=x;l>=0 && !(*fkt)(a,base[sort_a[l]]);l--);
   l++;
   *unten=l;

   for(r=x;r<cnt && !(*fkt)(a,base[sort_a[r]]);r++);
   r--;
   *anzahl=r-l+1;
   return OK;
}

/* Funktion qcmp_sorti() +§§§3 */
static int qcmp_sorti(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=sorti_buf[a]-sorti_buf[b]))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_sortc() +§§§3 */
static int qcmp_sortc(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=stri_cmp(sortc_buf[a],sortc_buf[b])))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_bic_h() +§§§3 */
static int qcmp_bic_h(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=stri_cmp(bic_h[a],bic_h[b])))
      return r;
   else 
      return a-b;
}


/* Funktion qcmp_bic() +§§§3 */
static int qcmp_bic(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=stri_cmp(bic[a],bic[b])))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_name() +§§§3 */
static int qcmp_name(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=stri_cmp(name[a],name[b])))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_name_kurz() +§§§3 */
static int qcmp_name_kurz(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=stri_cmp(name_kurz[a],name_kurz[b])))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_ort() +§§§3 */
static int qcmp_ort(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=stri_cmp(ort[a],ort[b])))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_blz() +§§§3 */
static int qcmp_blz(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=blz[a]-blz[b]))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_pz_f() +§§§3 */
static int qcmp_pz_f(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=pz_f[a]-pz_f[b]))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_plz() +§§§3 */
static int qcmp_plz(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=plz[a]-plz[b]))
      return r;
   else 
      return a-b;
}

/* Funktion qcmp_iban_regel() +§§§3 */
static int qcmp_iban_regel(const void *ap,const void *bp)
{
   int a,b,r;

   a=*((int *)ap);
   b=*((int *)bp);
   if((r=iban_regel[a]-iban_regel[b]))
      return r;
   else 
      return a-b;
}

/* Funktion init_blzf() +§§§2
 * Diese Funktion initialisiert das Array mit den Bankleitzahlen für alle
 * Indizes (blz_f) und das Zweigstellen-Array (für Index -> Zweigstelle).
 */
static int init_blzf(int *cnt_p)
{
   int cnt,i,j,n,k;

   if(cnt_p)*cnt_p=0;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(startidx[lut2_cnt_hs-1]==lut2_cnt_hs-1){  /* keine Filialen in der Datei enthalten */
      cnt=lut2_cnt_hs;
      blz_f=blz;     /* die einfache BLZ-Tabelle reicht aus */
      pz_f=pz_methoden;
         /* Zweigstellen-Array, komplett mit Nullen initialisiert (per calloc; keine Zweigstellen) */
      if(!zweigstelle_f && !(zweigstelle_f=(int *)calloc(cnt+10,sizeof(int))))return ERROR_MALLOC;
   }
   else
      cnt=lut2_cnt;
   if(!blz_f){   /* Bankleitzahlen mit Filialen; eigenes Array erforderlich */
      if(!(blz_f=(int *)calloc(cnt+10,sizeof(int))))return ERROR_MALLOC;
      if(!(zweigstelle_f=(int *)calloc(cnt+10,sizeof(int)))){
         FREE(blz_f);
         return ERROR_MALLOC;
      }
      if(!(pz_f=(int *)calloc(cnt+10,sizeof(int)))){
         FREE(blz_f);
         FREE(zweigstelle_f);
         return ERROR_MALLOC;
      }
      for(i=j=0;i<lut2_cnt_hs;i++)if((n=filialen[i])>1){
         for(k=0;k<n;k++){
            zweigstelle_f[j]=k;
            blz_f[j]=blz[i];
            pz_f[j++]=pz_methoden[i];
         }
      }
      else{
         zweigstelle_f[j]=0;
         blz_f[j++]=blz[i];
      }
   }
   if(cnt_p)*cnt_p=cnt;
   return OK;
}

DLL_EXPORT int kto_check_idx2blz(int idx,int *zweigstelle,int *retval)
{
   return konto_check_idx2blz(idx,zweigstelle,retval);
}

DLL_EXPORT int konto_check_idx2blz(int idx,int *zweigstelle,int *retval)
{
   int ret;
   if(!blz_f && (ret=init_blzf(NULL))<0){
      if(retval)*retval=ret;
      if(zweigstelle)*zweigstelle=0;
      return 0;
   }
   if(retval)*retval=OK;
   if(zweigstelle)*zweigstelle=zweigstelle_f[idx];
   return blz_f[idx];
}

/* Funktion suche_int1() +§§§2 */
static int suche_int1(int a1,int a2,int *anzahl,int **start_idx,int **zweigstellen_base,int **blz_base,
      int **base_name,int **base_sort,int(*cmp)(const void *, const void *),int cnt,int such_idx)
{
   char *data,*ptr;
   const char *lut_name;
   int i,cnt1,unten,retval,*b_sort,lut_set;
   UINT4 len;

   if(!a2)a2=a1;
   b_sort=*base_sort;
   if(!b_sort){
      lut_name=current_lutfile_name(&lut_set,NULL,&retval);
      if(retval!=OK){   /* nicht initialisiert */
         FREE(blz_f);
         FREE(zweigstelle_f);
         return retval;
      }
         /* versuchen, den Indexblock aus der LUT-Datei zu lesen */
      if(lut_set==2)such_idx+=100;
      retval=read_lut_block((char*)lut_name,such_idx,&len,&data);
      if(retval==OK){
         ptr=data;
         C2UI(cnt1,ptr);
         if(!(b_sort=(int *)malloc(cnt1*sizeof(int)))){
            FREE(blz_f);
            FREE(zweigstelle_f);
            return ERROR_MALLOC;
         }
         for(i=0;i<cnt1;i++)C2UI(b_sort[i],ptr);
         free(data);
      }
      else{
            /* Indexblock nicht gefunden, Index jetzt aufbauen */
         if(!(b_sort=(int *)calloc(cnt+10,sizeof(int))))return ERROR_MALLOC;
         for(i=0;i<cnt;i++)b_sort[i]=i;
         qsort(b_sort,cnt,sizeof(int),cmp);
      }
      *base_sort=b_sort;   /* Variable an aufrufende Funktion zurückgeben */
   }
   if((retval=binary_search_int(a1,a2,*base_name,b_sort,cnt,&unten,&cnt))!=OK){
      if(anzahl)*anzahl=0;
      if(start_idx)*start_idx=NULL;
      return retval;
   }
   if(anzahl)*anzahl=cnt;
   if(start_idx)*start_idx=b_sort+unten;
   return OK;
}

/* Funktion suche_int2() +§§§2 */
static int suche_int2(int a1,int a2,int *anzahl,int **start_idx,int **zweigstellen_base,int **blz_base,
      int **base_name,int **base_sort,int(*cmp)(const void *, const void *),int such_idx,int pz_suche)
{
   char *data,*ptr;
   const char *lut_name;
   int i,j,k,ix,cnt,cnt1,unten,retval,*b_sort,lut_set;
   UINT4 len;

   if(!a2)a2=a1;
   if((retval=init_blzf(&cnt))<0)return retval;
   cnt1=cnt;   /* nur gegen gcc-Warnung */
   b_sort=*base_sort;
   if(!b_sort){
      lut_name=current_lutfile_name(&lut_set,NULL,&retval);
      if(retval!=OK){   /* nicht initialisiert */
         FREE(blz_f);
         FREE(zweigstelle_f);
         return retval;
      }
         /* versuchen, den Indexblock aus der LUT-Datei zu lesen */
      if(lut_set==2)such_idx+=100;
      retval=read_lut_block((char*)lut_name,such_idx,&len,&data);
      if(retval==OK){
         ptr=data;
         if(pz_suche)
            C2UI(cnt1,ptr);
         else
            C2UI(cnt,ptr);
         if(!(b_sort=(int *)malloc(cnt*sizeof(int)))){
            if(blz_f!=blz)
               FREE(blz_f);
            else
               blz_f=NULL;
            FREE(zweigstelle_f);
            return ERROR_MALLOC;
         }
         if(pz_suche){
            if(base_name)*base_name=pz_f;
            for(i=ix=0;i<cnt1;i++){
               C2UI(j,ptr);
               for(k=0;k<filialen[j];k++){
                  b_sort[ix++]=startidx[j]+k; /* alle Filialen eintragen */
                  pz_f[startidx[j]+k]=pz_methoden[j]; /* Prüfziffermethode für die Filialen */
               }
            }
         }
         else
            for(i=0;i<cnt;i++)C2UI(b_sort[i],ptr);
         free(data);
      }
      else{
            /* Indexblock nicht gefunden, Index jetzt aufbauen */
         if(!(b_sort=(int *)calloc(cnt+10,sizeof(int)))){
            if(blz_f!=blz)
               FREE(blz_f);
            else
               blz_f=NULL;
            FREE(zweigstelle_f);
            return ERROR_MALLOC;
         }
         if(pz_suche){     /* Prüfziffermethode für die Filialen eintragen */
            if(base_name)*base_name=pz_f;
            for(i=0;i<cnt1;i++)
               for(k=0;k<filialen[i];k++)pz_f[startidx[i]+k]=pz_methoden[i];
         }
         for(i=0;i<cnt;i++)b_sort[i]=i;
         qsort(b_sort,cnt,sizeof(int),cmp);
      }
      *base_sort=b_sort;   /* Variable an aufrufende Funktion zurückgeben */
   }
   if((retval=binary_search_int(a1,a2,*base_name,b_sort,cnt,&unten,&cnt))!=OK){
      if(anzahl)*anzahl=0;
      if(start_idx)*start_idx=NULL;
      RETURN(retval);
   }
   if(blz_base)*blz_base=blz_f;
   if(zweigstellen_base)*zweigstellen_base=zweigstelle_f;
   if(anzahl)*anzahl=cnt;
   if(start_idx)*start_idx=b_sort+unten;
   return OK;
}

/* Funktion suche_str() +§§§2 */
static int suche_str(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,int **blz_base,
      char ***base_name,int **base_sort,int(*cmp)(const void *, const void *),UINT4 such_idx)
{
   char *data,*ptr;
   const char *lut_name;
   int i,cnt,unten,retval,*b_sort,lut_set;
   UINT4 len;

   if((retval=init_blzf(&cnt))<0)return retval;
   if(blz_base)*blz_base=blz_f;
   if(zweigstellen_base)*zweigstellen_base=zweigstelle_f;
   b_sort=*base_sort;
   if(!b_sort){
         /* Dateinamen und Set der aktuellen Initialisierung holen */
      lut_name=current_lutfile_name(&lut_set,NULL,&retval);
      if(retval!=OK){   /* nicht initialisiert */
         FREE(blz_f);
         FREE(zweigstelle_f);
         return retval;
      }
         /* versuchen, den Indexblock aus der LUT-Datei zu lesen */
      if(lut_set==2)such_idx+=100;
      retval=read_lut_block((char*)lut_name,such_idx,&len,&data);
      if(retval==OK){
         ptr=data;
         C2UI(cnt,ptr);
         if(!(b_sort=(int *)malloc(cnt*sizeof(int)))){
            FREE(blz_f);
            FREE(zweigstelle_f);
            return ERROR_MALLOC;
         }
         for(i=0;i<cnt;i++)C2UI(b_sort[i],ptr);
         free(data);
      }
      else{
            /* Indexblock nicht gefunden, Index jetzt aufbauen */
         if(!(b_sort=(int *)calloc(cnt+10,sizeof(int)))){
            FREE(blz_f);
            FREE(zweigstelle_f);
            return ERROR_MALLOC;
         }
         for(i=0;i<cnt;i++)b_sort[i]=i;
         qsort(b_sort,cnt,sizeof(int),cmp);
      }
      *base_sort=b_sort;   /* Variable an aufrufende Funktion zurückgeben */
   }
   if((retval=binary_search(such_name,*base_name,b_sort,cnt,&unten,&cnt))!=OK){
      if(anzahl)*anzahl=0;
      if(start_idx)*start_idx=NULL;
      RETURN(retval);
   }
   if(anzahl)*anzahl=cnt;
   if(start_idx)*start_idx=b_sort+unten;
   return OK;
}

/* Funktion lut_suche_multiple_and() +§§§2 */
/* Diese Funktion  bekommt als Eingangsparameter das Ergebnis einer oder zweier
 * Suchfunktionen (in der Form zweier Integer-Pointer *start1 und *start2 sowie
 * der zugehörigen Anzahlen cnt1 und cnt2, wie sie von den normalen
 * Suchroutinen zurückgegeben werden) sowie (optional) den Ausgabe-Parameter
 * *such_array, der ein Integerarray mit lut2_cnt Elementen ist, bei dem jedes
 * Element für eine Bank steht. Falls such_array nicht angegeben ist, wird es
 * initialisiert. Das weitere Verhalten hängt von den Parametern start1 und
 * start2 ab:
 *
 *    - falls nur start1 angegeben ist, werden in such_array alle Banken auf 1
 *      gesetzt, die in dem Array start1 angegeben sind.
 *    - falls start1 und start2 angegeben sind, werden nur die Banken auf 1
 *      gesetzt, die in beiden Arrays angegeben sind.
 *
 * Die Variante daß nur start1 angegeben ist wird benutzt, um die interne
 * Darstellung auf die in dieser Funktionsgruppe benutzte Version umzusetzen.
 * Das Ausgabearray (such_array) ist dabei nach Banken sortiert.
 */
static int *lut_suche_multiple_and(int *such_array,int *start1,int cnt1,int *start2,int cnt2,int *cnt,int *retval)
{
   int i,min_val;

   if(cnt)*cnt=lut2_cnt;
   if(!such_array){
      if(!(such_array=(int *)calloc(sizeof(int),lut2_cnt))){
         if(retval)*retval=ERROR_MALLOC;
         return NULL;
      }
      min_val=2;
   }
   else
      min_val=3;
   if(start2)min_val+=4;
   for(i=0;i<lut2_cnt;i++)if(such_array[i])such_array[i]=1;
   if(start1)for(i=0;i<cnt1;i++)such_array[start1[i]]|=2;
   if(start2)for(i=0;i<cnt2;i++)such_array[start2[i]]|=4;
   for(i=0;i<lut2_cnt;i++)if(such_array[i]<min_val)
      such_array[i]=0;
   else
      such_array[i]=1;
   if(retval)*retval=OK;
   return such_array;
}

/* Funktion lut_suche_multiple_or() +§§§2 */
static int *lut_suche_multiple_or(int *such_array1,int **such_array2,int *cnt)
{
   int i;

   if(cnt)*cnt=lut2_cnt;
   if(!*such_array2)return such_array1;
   if(!such_array1){
      such_array1=*such_array2;
      *such_array2=NULL;
      return such_array1;
   }
   for(i=0;i<lut2_cnt;i++)if(such_array1[i] || (*such_array2)[i])such_array1[i]=1;
   FREE(*such_array2);
   return such_array1;
}

/* Funktion lut_suche_multiple_not() +§§§2 */
static int *lut_suche_multiple_not(int *such_array1,int **such_array2,int *cnt)
{
   int i;

   if(cnt)*cnt=lut2_cnt;
   if(!*such_array2)return such_array1;
   if(!such_array1){
      such_array1=*such_array2;
      *such_array2=NULL;
      for(i=0;i<lut2_cnt;i++)if(such_array1[i])
         such_array1[i]=0;
      else
         such_array1[i]=1;
      return such_array1;
   }
   else  /* nur bisher belegte Banken werden berücksichtigt */
      for(i=0;i<lut2_cnt;i++)if(such_array1[i])such_array1[i]=1;
   for(i=0;i<lut2_cnt;i++)if((*such_array2)[i])such_array1[i]=0;
   FREE(*such_array2);
   return such_array1;
}

DLL_EXPORT int lut_suche_init(int uniq)
{
   int i,id;
   LUT_SUCHE_ARR *a;

   if(!(a=(LUT_SUCHE_ARR *)calloc(sizeof(LUT_SUCHE_ARR),1)))return ERROR_MALLOC;
   if(!lut_suche_arr && !(lut_suche_arr=(LUT_SUCHE_ARR **)calloc(sizeof(LUT_SUCHE_ARR*),last_lut_suche_idx=100)))return ERROR_MALLOC;
   for(i=id=0;i<last_lut_suche_idx;i++)if(!lut_suche_arr[i]){  /* freien Index suchen */
      id=i;
      break;
   }
   if(i==last_lut_suche_idx){ /* der buffer wird zu klein, mehr allokieren */
      if(!(lut_suche_arr=(LUT_SUCHE_ARR **)realloc(lut_suche_arr,sizeof(LUT_SUCHE_ARR*)*(last_lut_suche_idx+=100))))return ERROR_MALLOC;
      for(id=i++;i<last_lut_suche_idx;i++)lut_suche_arr[i]=NULL;
   }
   lut_suche_arr[id]=a;
   a->uniq=uniq;
   return id;
}

DLL_EXPORT int lut_suche_free(int id)
{
   int i;
   LUT_SUCHE_ARR *a;

   if(id<0 || id>=last_lut_suche_idx || !lut_suche_arr[id])return LUT_SUCHE_INVALID_RSC;
   a=lut_suche_arr[id];
   for(i=0;i<LUT_SUCHE_MAX_CNT;i++)FREE(a->suche[i].suche_str); /* Suchstrings waren mit strdup kopiert */
   free(a);                   /* Struktur selbst freigeben */
   lut_suche_arr[id]=NULL;    /* Slot als frei markieren */
   return OK;
}

DLL_EXPORT int lut_suche_set(int such_id,int idx,int typ,int i1,int i2,char *txt)
{
   int ret;
   LUT_SUCHE_ARR *a;

   if(such_id<0 || such_id>=last_lut_suche_idx || !lut_suche_arr[such_id])return LUT_SUCHE_INVALID_RSC;
   a=lut_suche_arr[such_id];
   ret=OK;

   if(isupper(idx)){    /* testweise die Suche durchführen, bei Fehler Rückgabe des Statuscodes */
      idx=idx-'A';
      switch(typ){
         case LUT_SUCHE_VOLLTEXT:
            if((ret=lut_suche_volltext(txt,NULL,NULL,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_BIC:
            if((ret=lut_suche_bic(txt,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_BIC_H:
            if((ret=lut_suche_bic_h(txt,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_NAMEN:
            if((ret=lut_suche_namen(txt,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_NAMEN_KURZ:
            if((ret=lut_suche_namen_kurz(txt,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_ORT:
            if((ret=lut_suche_ort(txt,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_BLZ:
            if((ret=lut_suche_blz(i1,i2,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_PLZ:
            if((ret=lut_suche_plz(i1,i2,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
        case LUT_SUCHE_REGEL:
            if((ret=lut_suche_regel(i1,i2,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_PZ:
            if((ret=lut_suche_pz(i1,i2,NULL,NULL,NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         default:
            break;
      }
   }
   else
      idx=idx-'a';

   if(!a->suche[idx].such_typ && typ)a->anzahl++;
   a->suche[idx].such_typ=typ;
   a->suche[idx].suche_int1=i1;
   a->suche[idx].suche_int2=i2;
   if(txt){
      if(!(a->suche[idx].suche_str=strdup(txt)))return ERROR_MALLOC;
   }
   else
      a->suche[idx].suche_str=NULL;
   return ret;
}

DLL_EXPORT int lut_suche(int such_id,char *such_cmd,UINT4 *such_cnt,UINT4 **filiale,UINT4 **blz)
{
   char *ptr;
   int cnt,i,j,ret,typ,arr_cnt,last_blz,key_not_found,*s,*s1,*s2;
   LUT_SUCHE *such_array;
   LUT_SUCHERGEBNIS ergebnis;
   LUT_SUCHE_ARR *suche;

   if(such_id<0 || such_id>=last_lut_suche_idx || !lut_suche_arr[such_id])return LUT_SUCHE_INVALID_RSC;
   suche=lut_suche_arr[such_id];
   such_array=suche->suche;
   cnt=suche->anzahl;
   if(blz)*blz=NULL;    /* Initialisierung für den Fehlerfall */
   if(filiale)*filiale=NULL;
   if(such_cnt)*such_cnt=0;
   if((ret=init_blzf(NULL))<0)return ret;
   if(cnt<1 || cnt>LUT_SUCHE_MAX_CNT)return LUT_SUCHE_INVALID_CNT;

   for(i=key_not_found=0;i<LUT_SUCHE_MAX_CNT;i++){
      switch(such_array[i].such_typ){
         case LUT_SUCHE_VOLLTEXT:
            if((ret=lut_suche_volltext(such_array[i].suche_str,NULL,NULL,NULL,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_BIC:
            if((ret=lut_suche_bic(such_array[i].suche_str,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_BIC_H:
            if((ret=lut_suche_bic_h(such_array[i].suche_str,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_NAMEN:
            if((ret=lut_suche_namen(such_array[i].suche_str,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_NAMEN_KURZ:
            if((ret=lut_suche_namen_kurz(such_array[i].suche_str,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_ORT:
            if((ret=lut_suche_ort(such_array[i].suche_str,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_BLZ:
            if((ret=lut_suche_blz(such_array[i].suche_int1,such_array[i].suche_int2,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_PLZ:
            if((ret=lut_suche_plz(such_array[i].suche_int1,such_array[i].suche_int2,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_REGEL:
            if((ret=lut_suche_regel(such_array[i].suche_int1,such_array[i].suche_int2,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         case LUT_SUCHE_PZ:
            if((ret=lut_suche_pz(such_array[i].suche_int1,such_array[i].suche_int2,
                        &(ergebnis[i].cnt),&(ergebnis[i].start_idx),NULL,NULL,NULL))<0 && ret!=KEY_NOT_FOUND)return ret;
            break;
         default:
            ergebnis[i].cnt=0;
            ergebnis[i].start_idx=NULL;
            ret=0;
            break;
      }
      if(ret==KEY_NOT_FOUND)key_not_found=1;
   }
   for(s=s1=s2=NULL,typ=SUCHE_STD,ptr=such_cmd;*ptr;ptr++){
      if(*ptr=='+'){
         if(typ==SUCHE_STD)
            s=lut_suche_multiple_or(s,&s1,NULL);
         else
            s=lut_suche_multiple_not(s,&s1,NULL);
         typ=SUCHE_STD;
      }
      else if(*ptr=='-'){
         if(typ==SUCHE_STD)
            s=lut_suche_multiple_or(s,&s1,NULL);
         else
            s=lut_suche_multiple_not(s,&s1,NULL);
         typ=SUCHE_NOT;
      }
      else if(*ptr==' ')
         continue;
      else{
         if(!isalpha(*ptr))return LUT_SUCHE_INVALID_CMD;
         i=tolower(*ptr)-'a';
         s1=lut_suche_multiple_and(s1,ergebnis[i].start_idx,ergebnis[i].cnt,NULL,0,NULL,&ret);
         if(ret<OK)return ret;
      }
   }
   if(typ==SUCHE_STD)
      s=lut_suche_multiple_or(s,&s1,&arr_cnt);
   else
      s=lut_suche_multiple_not(s,&s1,&arr_cnt);

   if(s){
      for(i=cnt=0;i<arr_cnt;i++)if(s[i])cnt++;
      if(blz && !(*blz=(UINT4 *)malloc(cnt*4)))return ERROR_MALLOC;
      if(filiale && !(*filiale=(UINT4 *)malloc(cnt*4)))return ERROR_MALLOC;
      last_blz=-1;
      if(suche->uniq){ /* hier muß nicht mehr sortiert werden, da die BLZs schon sortiert sind */
         for(i=j=cnt=0;i<arr_cnt;i++)if(s[i] && blz_f[i]!=last_blz){
            cnt++;
            last_blz=blz_f[i];
            if(blz)(*blz)[j]=blz_f[i];
            if(filiale)(*filiale)[j++]=zweigstelle_f[i];
         }
      }
      else
         for(i=j=0;i<arr_cnt;i++)if(s[i]){
            if(blz)(*blz)[j]=blz_f[i];
            if(filiale)(*filiale)[j++]=zweigstelle_f[i];
         }
      if(such_cnt)*such_cnt=cnt;
      free(s);
   }
   if(key_not_found)
      return SOME_KEYS_NOT_FOUND;
   else
      return OK;
}

/* Funktion lut_suche_multiple() +§§§2 */
DLL_EXPORT int lut_suche_multiple(char *such_str,int uniq,char *such_cmd,UINT4 *anzahl,UINT4 **zweigstellen,UINT4 **blz)
{
   char *ptr,*ptr1,*pi2,*such_text,such_cmd1[LUT_SUCHE_MAX_CNT+1];
   int c,j,i1,i2,idx,ret,such_id,typ,genau,key_not_found;

   if(anzahl)*anzahl=0;
   if(blz)*blz=NULL;
   if(such_cmd && !*such_cmd)such_cmd=NULL;
   if(zweigstellen)*zweigstellen=NULL;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!such_str || !*such_str)return OK;
   if((such_id=lut_suche_init(uniq))<0)return such_id;
   if(!(such_text=strdup(such_str)))return ERROR_MALLOC;
   key_not_found=0;
   if(*(ptr=such_text)=='!'){
      genau=1;
      ptr++;  /* erstmal ignorieren, später wieder einfügen */
   }
   else
      genau=0;
   while(!volltext_zeichen(UCPP &ptr))ptr++; /* führende Blanks etc. entfernen */
   if(genau)*--ptr='!';    /* genau-Markierung wieder einfügen (u.U. an späterer Position) */
   for(c=0,j='a',ptr1=pi2=ptr;*ptr && j<='z';){
      if(*ptr1=='!'){
         genau=1;
         ptr++;
         ptr1++;
      }
      else
         genau=0;

      if(*(ptr+1)==':' && isascii(*ptr)){    /* Suchindex angegeben (a:...) */
         idx=*ptr;
         ptr+=2;
         ptr1=pi2=ptr;
      }
      else
         idx=j;
      while(volltext_zeichen(UCPP &ptr))ptr++;
      typ=LUT_SUCHE_VOLLTEXT;
      i1=i2=0;
      if(*ptr=='-'){    /* Bereich (für numerische Suche) angegeben */
         pi2=++ptr;
         while(volltext_zeichen(UCPP &ptr))ptr++;
      }
      if(*ptr=='@'){    /* Suchfeld angegeben */
         *ptr++=0;
         switch(tolower(*ptr++)){
            case 'b':
               if(tolower(*ptr)=='l')
                  typ=LUT_SUCHE_BLZ;
               else if(tolower(*ptr)=='i')
                  typ=LUT_SUCHE_BIC;
               else if(tolower(*ptr)=='h')
                  typ=LUT_SUCHE_BIC_H;
               break;

            case 'k':
               typ=LUT_SUCHE_NAMEN_KURZ;
               break;

            case 'n':
               typ=LUT_SUCHE_NAMEN;
               break;

            case 'o':
               typ=LUT_SUCHE_ORT;
               break;

            case 'p':
               if(tolower(*ptr)=='l')
                  typ=LUT_SUCHE_PLZ;
               else if(tolower(*ptr)=='z' || tolower(*ptr)=='r')
                  typ=LUT_SUCHE_PZ;
               break;

            case 'r':
               typ=LUT_SUCHE_REGEL;
               break;

            case 'v':
               typ=LUT_SUCHE_VOLLTEXT;
               break;

            default:
               break;
         }
         i1=atoi(ptr1);
         i2=atoi(pi2);
         while(volltext_zeichen(UCPP &ptr))ptr++;
         while(*ptr && !volltext_zeichen(UCPP &ptr) && *ptr!='!')ptr++;
      }
      else
         while(*ptr && !volltext_zeichen(UCPP &ptr) && *ptr!='!')*ptr++=0;
      such_cmd1[c++]=idx;
      if(genau)*--ptr1='!';    /* such_text wurde mit strdup() angelegt und darf verändert werden */
      if((ret=lut_suche_set(such_id,idx,typ,i1,i2,ptr1))<0 && ret!=KEY_NOT_FOUND){
         free(such_text);
         lut_suche_free(such_id);
         return ret;
      }
      if(ret==KEY_NOT_FOUND)key_not_found=1;
      ptr1=ptr;
      j++;
   }
   such_cmd1[c]=0;
   ret=lut_suche(such_id,such_cmd?such_cmd:such_cmd1,anzahl,zweigstellen,blz);
   lut_suche_free(such_id);
   free(such_text);
   if(key_not_found || ret==KEY_NOT_FOUND)
      return SOME_KEYS_NOT_FOUND;
   else
      return ret;
}

/* cmp_suche_sort(): Sortierfunktion für lut_suche_ort() +§§§2 */
static int *blz_suche_sort,*zw_suche_sort;   /* Hilfsvariablen */

static int cmp_suche_sort(const void *ap,const void *bp)
{
   int a,b;

   a=*(int*)ap;
   b=*(int*)bp;
   if(blz_suche_sort[a]!=blz_suche_sort[b])return blz_suche_sort[a]-blz_suche_sort[b];
   if(zw_suche_sort[a]!=zw_suche_sort[b])return zw_suche_sort[a]-zw_suche_sort[b];
   return a-b;
}

/* Funktion lut_suche_sort1() +§§§2 */
DLL_EXPORT int lut_suche_sort1(int anzahl,int *blz_base,int *zweigstellen_base,int *idx,int *anzahl_o,int **idx_op,int **cnt_op,int uniq)
{
   int i,j,last_idx,*idx_a,*cnt_o;

   if(idx_op)*idx_op=NULL;
   if(cnt_op)*cnt_op=NULL;
   *anzahl_o=0;
   if(!(idx_a=(int *)malloc(anzahl*sizeof(int))))return ERROR_MALLOC;
   if(!(cnt_o=(int *)malloc(anzahl*sizeof(int))))return ERROR_MALLOC;
   for(i=0;i<anzahl;i++){ /* initialisieren */
      idx_a[i]=idx[i];
      cnt_o[i]=1;
   }
   blz_suche_sort=blz_base;
   zw_suche_sort=zweigstellen_base;
//#error lock für sort einfügen wegen globalem blz_suche_sort und zw_suche_xort oder besser spezifische Sortierroutinen
   qsort(idx_a,anzahl,sizeof(int),cmp_suche_sort);
   if(uniq){
      for(last_idx=-1,i=j=0;i<anzahl;i++){
         if(blz_base[idx_a[i]]==last_idx){
            cnt_o[j-1]++;  /* j wurde bereits inkrementiert */
            continue;
         }
         idx_a[j]=idx_a[i];
         last_idx=blz_base[idx_a[i]];
         j++;
      }
      if(!(idx_a=(int *)realloc(idx_a,j*sizeof(int))))return ERROR_MALLOC;
      if(!(cnt_o=(int *)realloc(cnt_o,j*sizeof(int))))return ERROR_MALLOC;
      *anzahl_o=j;
   }
   else
      *anzahl_o=anzahl;
   if(idx_op)
      *idx_op=idx_a;
   else
      free(idx_a);
   if(cnt_op)
      *cnt_op=cnt_o;
   else
      free(cnt_o);
   return OK;
}

/* Funktion lut_suche_sort2() +§§§2 */
DLL_EXPORT int lut_suche_sort2(int anzahl,int *blz,int *zweigstellen,int *anzahl_o,int **blz_op,int **zweigstellen_op,int **cnt_o,int uniq)
{
   int i,j,last_blz,*idx_a,*blz_o,*zweigstellen_o;

   idx_a=(int *)malloc(anzahl*sizeof(int));
   for(i=0;i<anzahl;i++)idx_a[i]=i; /* initialisieren */
   blz_suche_sort=blz;
   zw_suche_sort=zweigstellen;
// #error lock für sort einfügen wegen globalem blz_suche_sort und zw_suche_xort oder besser spezifische Sortierroutinen
   qsort(idx_a,anzahl,sizeof(int),cmp_suche_sort);
   blz_o=(int *)malloc(anzahl*sizeof(int));
   zweigstellen_o=(int *)malloc(anzahl*sizeof(int));
   if(uniq){
      for(last_blz=-1,i=j=0;i<anzahl;i++){
         if(blz[idx_a[i]]==last_blz)continue;
         cnt_o[j]++;
         blz_o[j]=blz[idx_a[i]];
         zweigstellen_o[j++]=zweigstellen[idx_a[i]];
         last_blz=blz[idx_a[i]];
      }
//      fprintf(stderr,"cnt_o: %d\n",j);
      if(!(blz_o=(int *)realloc(blz_o,j*sizeof(int))))return ERROR_MALLOC;
      if(!(cnt_o=(int **)realloc(cnt_o,j*sizeof(int))))return ERROR_MALLOC;
      *anzahl_o=j;
   }
   else{
      for(i=0;i<anzahl;i++){
         /************ HIER NOCH UNIQ EINBAUEN **************/
         blz_o[i]=blz[idx_a[i]];
         zweigstellen_o[i]=zweigstellen[idx_a[i]];
      }
      *anzahl_o=anzahl;
   }
   free(idx_a);
   *blz_op=blz_o;
   *zweigstellen_op=zweigstellen_o;
   return OK;
}

/* Funktion lut_suche_volltext() +§§§2 */
DLL_EXPORT int lut_suche_volltext(char *such_wort,int *anzahl,int *base_name_idx,char ***base_name,
      int *zweigstellen_anzahl,int **start_idx,int **zweigstellen_base,int **blz_base)
{
   const char *lut_name;
   char *data,*ptr,*ptr1;
   int i,j,k,lut_set,retval,unten;
   UINT4 len;

   if(anzahl)*anzahl=0;
   if(zweigstellen_anzahl)*zweigstellen_anzahl=0;
   if(base_name)*base_name=NULL;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if((retval=init_blzf(NULL))<0)return retval;
   if(blz_base)*blz_base=blz_f;
   if(zweigstellen_base)*zweigstellen_base=zweigstelle_f;

   if(!volltext){ /* die Volltext-Suche wurde noch nicht initialisiert */
         /* Dateinamen und Set der aktuellen Initialisierung holen */
      lut_name=current_lutfile_name(&lut_set,NULL,&retval);
      if(retval!=OK)return retval;   /* nicht initialisiert */

         /* versuchen, die Blocks aus der LUT-Datei zu lesen */
      retval=read_lut_block((char*)lut_name,LUT2_VOLLTEXT_TXT+(lut_set==2?100:0),&len,&volltext_data);
      if(retval!=OK)return retval;   
      ptr1=volltext_data+len; /* Ende des Buffers merken */
      retval=read_lut_block((char*)lut_name,LUT2_VOLLTEXT_IDX+(lut_set==2?100:0),&len,&data);
      if(retval!=OK)return retval;   
      ptr=data;
      C2UL(vt_cnt_uniq,ptr);
      C2UL(vt_cnt,ptr);
      if(!(volltext=(char **)malloc(vt_cnt*sizeof(char*)))){
         FREE(volltext_data);
         return ERROR_MALLOC;
      }
      if(!(volltext_start=(int *)malloc((vt_cnt_uniq+1)*sizeof(int)))){
         FREE(volltext);
         FREE(volltext_data);
         return ERROR_MALLOC;
      }
      if(!(sort_volltext=(int *)malloc(vt_cnt_uniq*sizeof(int)))){
         FREE(volltext);
         FREE(volltext_data);
         FREE(volltext_start);
         return ERROR_MALLOC;
      }
      if(!(volltext_banken=(int *)malloc(vt_cnt*sizeof(int)))){
         FREE(volltext);
         FREE(volltext_data);
         FREE(volltext_start);
         FREE(sort_volltext);
         return ERROR_MALLOC;
      }

         /* Volltext-Array mit Pointern auf die Daten füllen */
      for(*volltext=ptr=volltext_data,i=1;ptr<ptr1 && i<vt_cnt_uniq;)if(!*ptr++)volltext[i++]=ptr;

         /* Index-Arrays füllen */
      for(i=j=0,ptr=data+8;i<vt_cnt_uniq;i++){
         sort_volltext[i]=i;  /* eigentlich nur Dummy für suche_str() */
         volltext_start[i]=j;
         C2UI(k,ptr);
         j+=k;
      }
      volltext_start[i]=j;
      for(i=0;i<vt_cnt;i++)C2UI(volltext_banken[i],ptr);
      free(data);
   }
      /* einige häufiger vorkommende Sonderzeichen (die für die Volltextsuche ungültig sind) testen */
   for(ptr=such_wort;*ptr;)switch(*ptr++){
      case '-':
      case '\'':
      case ',':
      case '.':
      case '+':
      case '/':
      case '&':
      case '(':
      case ')':
         return LUT2_VOLLTEXT_INVALID_CHAR;
      default:
         break;
   }
   if(*(ptr=such_wort)=='!')ptr++;  /* ! am Wortanfang für exakte Suche zulassen */
   for(;*ptr;ptr++)if(!volltext_zeichen(UCPP &ptr))return LUT2_VOLLTEXT_SINGLE_WORD_ONLY;

   if((retval=binary_search(such_wort,volltext,sort_volltext,vt_cnt_uniq,&unten,&vt_cnt))!=OK){
      if(anzahl)*anzahl=0;
      if(start_idx)*start_idx=NULL;
      RETURN(retval);
   }

      /* die binäre Suche hat die Suchwörter im Array volltext[] gefunden; für
       * die Rückgabe müssen diese Werte auf das Array volltext_banken[]
       * umgesetzt werden (mittels des Arrays volltext_start[]).
       */
   if(anzahl)*anzahl=vt_cnt;
   if(base_name_idx)*base_name_idx=unten;
   if(zweigstellen_anzahl)*zweigstellen_anzahl=volltext_start[unten+vt_cnt]-volltext_start[unten];
   if(start_idx)*start_idx=volltext_banken+volltext_start[unten];
   if(base_name)*base_name=volltext;
   return OK;
}

DLL_EXPORT int lut_suche_blz(int such1,int such2,int *anzahl,int **start_idx,int **zweigstellen_base,int **base_name,int **blz_base)
{
   int i,cnt,ret;

   if(anzahl)*anzahl=0;
   if(such2 && such1>such2)return INVALID_SEARCH_RANGE;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!blz_f && (ret=init_blzf(NULL))<0)return ret;
   if(base_name)*base_name=blz_f;
   cnt=lut2_cnt;
   if(!sort_blz){
      if(!(sort_blz=(int *)malloc(cnt*sizeof(int))))return ERROR_MALLOC;
      for(i=0;i<cnt;i++)sort_blz[i]=i;
   }
   if(blz_base)*blz_base=blz_f;
   if(zweigstellen_base){
         /* Dummy-Array für die Zweigstellen anlegen (nur Nullen; für die Rückgabe erforderlich) */
      if(!zweigstelle_f && !(zweigstelle_f=(int *)calloc(cnt+10,sizeof(int))))return ERROR_MALLOC;
      *zweigstellen_base=zweigstelle_f;
   }
   return suche_int1(such1,such2,anzahl,start_idx,zweigstellen_base,blz_base,&blz_f,&sort_blz,qcmp_blz,cnt,0);
}

#line 23085 "konto_check.lxx"
/* Funktion lut_suche_bic() +§§§2 */
DLL_EXPORT int lut_suche_bic(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)
{
   if(anzahl)*anzahl=0;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!bic)return LUT2_BIC_NOT_INITIALIZED;   
   if(base_name)*base_name=bic;
   return suche_str(such_name,anzahl,start_idx,zweigstellen_base,blz_base,&bic,&sort_bic,qcmp_bic,LUT2_BIC_SORT);
}

/* Funktion lut_suche_namen() +§§§2 */
DLL_EXPORT int lut_suche_namen(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)
{
   if(anzahl)*anzahl=0;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!name)return LUT2_NAME_NOT_INITIALIZED;   
   if(base_name)*base_name=name;
   return suche_str(such_name,anzahl,start_idx,zweigstellen_base,blz_base,&name,&sort_name,qcmp_name,LUT2_NAME_SORT);
}

/* Funktion lut_suche_namen_kurz() +§§§2 */
DLL_EXPORT int lut_suche_namen_kurz(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)
{
   if(anzahl)*anzahl=0;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!name_kurz)return LUT2_NAME_KURZ_NOT_INITIALIZED;   
   if(base_name)*base_name=name_kurz;
   return suche_str(such_name,anzahl,start_idx,zweigstellen_base,blz_base,&name_kurz,&sort_name_kurz,qcmp_name_kurz,LUT2_NAME_KURZ_SORT);
}

/* Funktion lut_suche_ort() +§§§2 */
DLL_EXPORT int lut_suche_ort(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)
{
   if(anzahl)*anzahl=0;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!ort)return LUT2_ORT_NOT_INITIALIZED;   
   if(base_name)*base_name=ort;
   return suche_str(such_name,anzahl,start_idx,zweigstellen_base,blz_base,&ort,&sort_ort,qcmp_ort,LUT2_ORT_SORT);
}

/* Funktion lut_suche_pz() +§§§2 */
DLL_EXPORT int lut_suche_pz(int such1,int such2,int *anzahl,int **start_idx,int **zweigstellen_base,int **base_name,int **blz_base)
{
   int retval;

   if(anzahl)*anzahl=0;
   if(such2 && such1>such2)return INVALID_SEARCH_RANGE;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!pz_methoden)return LUT2_PZ_NOT_INITIALIZED;
   retval=suche_int2(such1,such2,anzahl,start_idx,zweigstellen_base,blz_base,&pz_f,&sort_pz_f,qcmp_pz_f,LUT2_PZ_SORT,1);
   if(base_name)*base_name=pz_f;
   return retval;
}

/* Funktion lut_suche_plz() +§§§2 */
DLL_EXPORT int lut_suche_plz(int such1,int such2,int *anzahl,int **start_idx,int **zweigstellen_base,int **base_name,int **blz_base)
{
   if(anzahl)*anzahl=0;
   if(such2 && such1>such2)return INVALID_SEARCH_RANGE;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!plz)return LUT2_PLZ_NOT_INITIALIZED;   
   if(base_name)*base_name=plz;
   return suche_int2(such1,such2,anzahl,start_idx,zweigstellen_base,blz_base,&plz,&sort_plz,qcmp_plz,LUT2_PLZ_SORT,0);
}

/* Funktion lut_suche_regel() +§§§2 */
DLL_EXPORT int lut_suche_regel(int such1,int such2,int *anzahl,int **start_idx,int **zweigstellen_base,int **base_name,int **blz_base)
{
   if(anzahl)*anzahl=0;
   if(such2 && such1>such2)return INVALID_SEARCH_RANGE;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!iban_regel)return LUT2_IBAN_REGEL_NOT_INITIALIZED;   
   if(base_name)*base_name=iban_regel;
   return suche_int2(such1*100,such2*100+99,anzahl,start_idx,zweigstellen_base,blz_base,&iban_regel,&sort_iban_regel,qcmp_iban_regel,LUT2_IBAN_REGEL_SORT,0);
}


/* Funktion lut_suche_bic_h() +§§§2 */
DLL_EXPORT int lut_suche_bic_h(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)
{
   if(anzahl)*anzahl=0;
   if((init_status&7)<7)return LUT2_NOT_INITIALIZED;
   if(lut_id_status==FALSE)return LUT1_FILE_USED;
   if(!bic_h)return LUT2_BIC_NOT_INITIALIZED;   
   if(base_name)*base_name=bic_h;
   return suche_str(such_name,anzahl,start_idx,zweigstellen_base,blz_base,&bic_h,&sort_bic_h,qcmp_bic_h,LUT2_BIC_H_SORT);
}

   /* Funktion bic_info() +§§§2
    * Die Funktion bic_info() sucht Banken mit einem bestimmten BIC und gibt
    * die gefundene Anzahl sowie den Startindex in den internen Arrays zurück.
    * Sie ist für die Funktionsgruppe biq_* gedacht, falls mehrere Werte aus der
    * BLZ-Datei bestimmt werden sollen (z.B. verschiedene Felder oder Werte für
    * mehrere Zweigstellen einer Bank). So erspart man sich die relativ aufwendige
    * Suche; sie ist nur einmal notwendig.
    *
    * Parameter:
    *    bic1: BIC zu dem die Banken bestimmt werden sollen (komplett oder teilweise)
    *    mode: Suchmodus; er kann die folgenden Werte annehmen:
    *          mode=1: Suche in allen BICs der BLZ-Datei (Haupt- und Nebenstellen)
    *          mode=2: Suche nur in den BICs der Hauptstellen
    *          mode=0: zunächst Suche bei den Hauptstellen, dann bei Haupt- und Nebenstellen;
    *                  falls dann noch nichts gefunden wurde, werden die drei letzten Stellen
    *                  (Filialcode) mit XXX gefüllt und noch einmal eine Suche gemacht.
    *   anzahl: in diesem Parameter wird die Anahl der gefundenen Banken zurückgegeben
    *   start_idx: Startindex in den internen Arrays, positiv für das Hauptstellen-Array, 
    *              negativ für das allgemeine BIC-Array. Dieser Index wird als Parameter für
    *              die Funktionsgruppe biq_* benutzt.
    */
DLL_EXPORT int bic_info(char *bic1,int mode,int *anzahl,int *start_idx)
{
   char *ptr,bic2[12];
   int *s_idx,retval,cnt;

   switch(mode){
      case 0:
      default:
         retval=lut_suche_bic_h(bic1,&cnt,&s_idx,NULL,NULL,NULL);
         if(start_idx)*start_idx=(s_idx-sort_bic_h)+1;
         if(!cnt){   /* Suche bei allen BICs (inklusive Nebenstellen) */
             retval=lut_suche_bic(bic1,&cnt,&s_idx,NULL,NULL,NULL);
            if(start_idx)*start_idx=(sort_bic-s_idx)-1;   /* negativer Startindex */
         }
         if(!cnt){   /* noch nichts gefunden, Zweigstellenteil des BIC mit XXX auffüllen (z.B. für Postbank) */
            memcpy(bic2,bic1,8); /* Hauptstellenteil kopieren */
            *(ptr=bic2+8)='X';   /* Nebenstellenteil mit 'X' füllen */
            *++ptr='X';
            *++ptr='X';
            *++ptr=0;
            retval=lut_suche_bic(bic2,&cnt,&s_idx,NULL,NULL,NULL);
            if(retval>=OK)retval=OK_SHORT_BIC_USED;
            if(start_idx)*start_idx=(sort_bic-s_idx)-1;   /* negativer Startindex */
         }
         break;
      case 1:
         retval=lut_suche_bic(bic1,&cnt,&s_idx,NULL,NULL,NULL);
         if(start_idx)*start_idx=(sort_bic-s_idx)-1;   /* negativer Startindex */
         break;
      case 2:
         retval=lut_suche_bic_h(bic1,&cnt,&s_idx,NULL,NULL,NULL);
         if(start_idx)*start_idx=(s_idx-sort_bic_h)+1;
         break;
   }
   if(anzahl)*anzahl=cnt;
   if(start_idx && !cnt)*start_idx=0;
   return retval;
}

/* Funktion bic_\bic_*(), biq_* und iban_* +§§§2 */
/* Diese Funktionen entsprechen weitgehend den Funktionen lut_*; sie können
 * benutzt werden, um Daten zu einem BIC oder einer IBAN zu bestimmen.
 *
 * Die Funktionen bic_*() bestimmen die Felder der BLZ-Datei zu einem BIC.
 * Der Parameter mode bestimmt dabei, wie der BIC gesucht wird (s.o. bei der
 * Funktion bic_info()). Zu einem BIC werden üblicherweise mehrere Banken gefunden;
 * diese werden nach BIC sortiert ausgegeben.
 *
 * Da der BIC nur ein sehr grobes Merkmal ist (bei der Postbank ist z.B. der Filialteil bei
 * allen Filialen auf XXX gesetzt, so daß alle Postbanken sich einen BIC teilen), wurden
 * zusätzlich noch die Funktion iban_*() implementiert. Diese entsprechen den vorhergehenden
 * Funktionen, bestimmen allerdings aus der IBAN  die BLZ und werten diese dann aus.
 */
/* Funktion bic_aenderung(), biq_aenderung und iban_aenderung +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen das Änderungsflag zu einem BIC bzw. einer IBAN   #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT int bic_aenderung(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_c(bic1,mode,filiale,retval,aenderung,LUT2_AENDERUNG_NOT_INITIALIZED);
}

DLL_EXPORT int biq_aenderung(int idx,int*retval)
{
   return biq_fkt_c(idx,retval,aenderung,LUT2_AENDERUNG_NOT_INITIALIZED);
}

DLL_EXPORT int iban_aenderung(char *iban,int filiale,int*retval)
{
   return iban_fkt_c(iban,filiale,retval,lut_aenderung);
}

/* Funktion bic_loeschung(), biq_loeschung und iban_loeschung +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen das Löschflag zu einem BIC bzw. einer IBAN       #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT int bic_loeschung(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_c(bic1,mode,filiale,retval,loeschung,LUT2_LOESCHUNG_NOT_INITIALIZED);
}

DLL_EXPORT int biq_loeschung(int idx,int*retval)
{
   return biq_fkt_c(idx,retval,loeschung,LUT2_LOESCHUNG_NOT_INITIALIZED);
}

DLL_EXPORT int iban_loeschung(char *iban,int filiale,int*retval)
{
   return iban_fkt_c(iban,filiale,retval,lut_loeschung);
}

/* Funktion bic_iban_regel(), biq_iban_regel und iban_iban_regel +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen die IBAN-Regel zu einem BIC bzw. einer IBAN      #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT int bic_iban_regel(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_i(bic1,mode,filiale,retval,iban_regel,LUT2_IBAN_REGEL_NOT_INITIALIZED);
}

DLL_EXPORT int biq_iban_regel(int idx,int*retval)
{
   return biq_fkt_i(idx,retval,iban_regel,LUT2_IBAN_REGEL_NOT_INITIALIZED);
}

DLL_EXPORT int iban_iban_regel(char *iban,int filiale,int*retval)
{
   return iban_fkt_i(iban,filiale,retval,lut_iban_regel);
}

/* Funktion bic_nachfolge_blz(), biq_nachfolge_blz und iban_nachfolge_blz +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen die Nachfolge-BLZ zu einem BIC bzw. einer IBAN   #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT int bic_nachfolge_blz(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_i(bic1,mode,filiale,retval,nachfolge_blz,LUT2_NACHFOLGE_BLZ_NOT_INITIALIZED);
}

DLL_EXPORT int biq_nachfolge_blz(int idx,int*retval)
{
   return biq_fkt_i(idx,retval,nachfolge_blz,LUT2_NACHFOLGE_BLZ_NOT_INITIALIZED);
}

DLL_EXPORT int iban_nachfolge_blz(char *iban,int filiale,int*retval)
{
   return iban_fkt_i(iban,filiale,retval,lut_nachfolge_blz);
}

/* Funktion bic_nr(), biq_nr und iban_nr +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen die Laufende Nr. zu einem BIC bzw. einer IBAN    #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT int bic_nr(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_i(bic1,mode,filiale,retval,bank_nr,LUT2_NR_NOT_INITIALIZED);
}

DLL_EXPORT int biq_nr(int idx,int*retval)
{
   return biq_fkt_i(idx,retval,bank_nr,LUT2_NR_NOT_INITIALIZED);
}

DLL_EXPORT int iban_nr(char *iban,int filiale,int*retval)
{
   return iban_fkt_i(iban,filiale,retval,lut_nr);
}

/* Funktion bic_pan(), biq_pan und iban_pan +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen den PAN zu einem BIC bzw. einer IBAN             #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT int bic_pan(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_i(bic1,mode,filiale,retval,pan,LUT2_PAN_NOT_INITIALIZED);
}

DLL_EXPORT int biq_pan(int idx,int*retval)
{
   return biq_fkt_i(idx,retval,pan,LUT2_PAN_NOT_INITIALIZED);
}

DLL_EXPORT int iban_pan(char *iban,int filiale,int*retval)
{
   return iban_fkt_i(iban,filiale,retval,lut_pan);
}

/* Funktion bic_plz(), biq_plz und iban_plz +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen die PLZ der Bank zu einem BIC bzw. einer IBAN    #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT int bic_plz(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_i(bic1,mode,filiale,retval,plz,LUT2_PLZ_NOT_INITIALIZED);
}

DLL_EXPORT int biq_plz(int idx,int*retval)
{
   return biq_fkt_i(idx,retval,plz,LUT2_PLZ_NOT_INITIALIZED);
}

DLL_EXPORT int iban_plz(char *iban,int filiale,int*retval)
{
   return iban_fkt_i(iban,filiale,retval,lut_plz);
}

/* Funktion bic_pz(), biq_pz und iban_pz +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen die Prüfziffer zu einem BIC bzw. einer IBAN      #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT int bic_pz(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_i(bic1,mode,filiale,retval,pz_methoden,LUT2_PZ_NOT_INITIALIZED);
}

DLL_EXPORT int biq_pz(int idx,int*retval)
{
   return biq_fkt_i(idx,retval,pz_methoden,LUT2_PZ_NOT_INITIALIZED);
}

DLL_EXPORT int iban_pz(char *iban,int filiale,int*retval)
{
   return iban_fkt_i(iban,filiale,retval,lut_pz);
}

/* Funktion bic_bic(), biq_bic und iban_bic +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen den BIC zu einem BIC bzw. einer IBAN             #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT const char *bic_bic(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_s(bic1,mode,filiale,retval,bic,LUT2_BIC_NOT_INITIALIZED);
}

DLL_EXPORT const char *biq_bic(int idx,int*retval)
{
   return biq_fkt_s(idx,retval,bic,LUT2_BIC_NOT_INITIALIZED);
}

DLL_EXPORT const char *iban_bic(char *iban,int filiale,int*retval)
{
   return iban_fkt_s(iban,filiale,retval,lut_bic);
}

/* Funktion bic_bic_h(), biq_bic_h und iban_bic_h +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen den BIC der Hauptstelle zu einem BIC bzw. einer IBAN#
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT const char *bic_bic_h(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_s(bic1,mode,filiale,retval,bic_h,LUT2_BIC_NOT_INITIALIZED);
}

DLL_EXPORT const char *biq_bic_h(int idx,int*retval)
{
   return biq_fkt_s(idx,retval,bic_h,LUT2_BIC_NOT_INITIALIZED);
}

DLL_EXPORT const char *iban_bic_h(char *iban,int filiale,int*retval)
{
   return iban_fkt_s(iban,filiale,retval,lut_bic_h);
}

/* Funktion bic_name(), biq_name und iban_name +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen den Name der Bank zu einem BIC bzw. einer IBAN   #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT const char *bic_name(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_s(bic1,mode,filiale,retval,name,LUT2_NAME_NOT_INITIALIZED);
}

DLL_EXPORT const char *biq_name(int idx,int*retval)
{
   return biq_fkt_s(idx,retval,name,LUT2_NAME_NOT_INITIALIZED);
}

DLL_EXPORT const char *iban_name(char *iban,int filiale,int*retval)
{
   return iban_fkt_s(iban,filiale,retval,lut_name);
}

/* Funktion bic_name_kurz(), biq_name_kurz und iban_name_kurz +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen den Kurzname der Bank zu einem BIC bzw. einer IBAN#
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT const char *bic_name_kurz(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_s(bic1,mode,filiale,retval,name_kurz,LUT2_NAME_KURZ_NOT_INITIALIZED);
}

DLL_EXPORT const char *biq_name_kurz(int idx,int*retval)
{
   return biq_fkt_s(idx,retval,name_kurz,LUT2_NAME_KURZ_NOT_INITIALIZED);
}

DLL_EXPORT const char *iban_name_kurz(char *iban,int filiale,int*retval)
{
   return iban_fkt_s(iban,filiale,retval,lut_name_kurz);
}

/* Funktion bic_ort(), biq_ort und iban_ort +§§§3 */
/* ###############################################################################
 * # Diese Funktionen bestimmen den Ort einer Bank zu einem BIC bzw. einer IBAN  #
 * #                                                                             #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>                 #
 * ###############################################################################
 */

DLL_EXPORT const char *bic_ort(char *bic1,int mode,int filiale,int*retval)
{
   return bic_fkt_s(bic1,mode,filiale,retval,ort,LUT2_ORT_NOT_INITIALIZED);
}

DLL_EXPORT const char *biq_ort(int idx,int*retval)
{
   return biq_fkt_s(idx,retval,ort,LUT2_ORT_NOT_INITIALIZED);
}

DLL_EXPORT const char *iban_ort(char *iban,int filiale,int*retval)
{
   return iban_fkt_s(iban,filiale,retval,lut_ort);
}

static int bic_fkt_c(char *bic1,int mode,int filiale,int *retval,char *base,int error)
{
   int cnt,start_idx,rv,ret1,ret2;

   if(!base){
      if(retval)*retval=error;
      return 0;
   }
   if((ret1=bic_info(bic1,mode,&cnt,&start_idx))<0){
      if(retval)*retval=ret1;
      return 0;
   }
   if(filiale>=cnt){
      if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
      return 0;
   }
   rv=biq_fkt_c(start_idx+filiale,&ret2,base,error);
   if(retval){
      if(ret2<0)
         *retval=ret2;
      else
         *retval=ret1;
   }
   return rv;
}

static int biq_fkt_c(int idx,int *retval,char *base,int error)
{
   int ret;

   if(!base){
      if(retval)*retval=error;
      return 0;
   }
   if(!idx){   /* Index 0 ist für Fehlerzustand reserviert */
      if(retval)*retval=INVALID_BIQ_INDEX;
      return 0;
   }
   else if(idx>0)
      idx--;
   else
      idx++;
   if(idx>0){
      if(idx>lut2_cnt){  /* der Test ist nur sehr grob, aber es gibt an dieser Stelle nicht mehr Infos */
         if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
         return 0;
      }
      if(!sort_bic_h){
         ret=lut_suche_bic_h("MARKDEF1100",NULL,NULL,NULL,NULL,NULL);  /* sort_bic_h initialisieren */
         if(ret<0){
            if(retval)*retval=ret;
            return 0;
         }
      }
      if(retval)*retval=OK;
      return (int)base[sort_bic_h[idx]];
   }
   else{
      idx=-idx;
      if(idx>lut2_cnt){
         if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
         return 0;
      }
      if(!sort_bic){
         ret=lut_suche_bic("MARKDEF1100",NULL,NULL,NULL,NULL,NULL);  /* sort_bic initialisieren */
         if(ret<0){
            if(retval)*retval=ret;
            return 0;
         }
      }
      if(retval)*retval=OK;
      return (int)base[sort_bic[idx]];
   }
}

static int iban_fkt_c(char *iban,int filiale,int *retval,int(*fkt)(char*,int,int*))
{
   char blz[9];

      /* nur zwei kleine Tests */
   if((*iban!='d' && *iban!='D') || (iban[1]!='e' && iban[1]!='E')){
      if(retval)*retval= IBAN_ONLY_GERMAN;
      return 0;
   }
   if(strlen(iban)!=22){
      if(retval)*retval=INVALID_IBAN_LENGTH;
      return 0;
   }

   memcpy(blz,iban+4,8);
   *(blz+8)=0;
   return fkt(blz,filiale,retval);
}

static int bic_fkt_i(char *bic1,int mode,int filiale,int *retval,int *base,int error)
{
   int cnt,start_idx,rv,ret1,ret2;

   if(!base){
      if(retval)*retval=error;
      return 0;
   }
   if((ret1=bic_info(bic1,mode,&cnt,&start_idx))<0){
      if(retval)*retval=ret1;
      return 0;
   }
   if(filiale>=cnt){
      if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
      return 0;
   }
   rv=biq_fkt_i(start_idx+filiale,&ret2,base,error);
   if(retval){
      if(ret2<0)
         *retval=ret2;
      else
         *retval=ret1;
   }
   return rv;
}

static int biq_fkt_i(int idx,int *retval,int *base,int error)
{
   int ret;

   if(!base){
      if(retval)*retval=error;
      return 0;
   }
   if(!idx){   /* Index 0 ist für Fehlerzustand reserviert */
      if(retval)*retval=INVALID_BIQ_INDEX;
      return 0;
   }
   else if(idx>0)
      idx--;
   else
      idx++;
   if(idx>0){
     if(idx>lut2_cnt){  /* der Test ist nur sehr grob, aber es gibt an dieser Stelle nicht mehr Infos */
        if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
        return 0;
     }
     if(!sort_bic_h){
        ret=lut_suche_bic_h("MARKDEF1100",NULL,NULL,NULL,NULL,NULL);  /* sort_bic_h initialisieren */
        if(ret<0){
           if(retval)*retval=ret;
           return 0;
        }
     }
     if(retval)*retval=OK;
     if(base==pz_methoden)
        return  base[startidx_r[sort_bic_h[idx]]];
     else
        return base[sort_bic_h[idx]];
   }
   else{
      idx=-idx;
      if(idx>lut2_cnt){
         if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
         return 0;
      }
      if(!sort_bic){
         ret=lut_suche_bic("MARKDEF1100",NULL,NULL,NULL,NULL,NULL);  /* sort_bic initialisieren */
         if(ret<0){
            if(retval)*retval=ret;
            return 0;
         }
      }
      if(retval)*retval=OK;
      return base[sort_bic[idx]];
   }
}

static int iban_fkt_i(char *iban,int filiale,int *retval,int(*fkt)(char*,int,int*))
{
   char blz[9];

      /* nur zwei kleine Tests */
   if((*iban!='d' && *iban!='D') || (iban[1]!='e' && iban[1]!='E')){
      if(retval)*retval= IBAN_ONLY_GERMAN;
      return 0;
   }
   if(strlen(iban)!=22){
      if(retval)*retval=INVALID_IBAN_LENGTH;
      return 0;
   }

   memcpy(blz,iban+4,8);
   *(blz+8)=0;
   return fkt(blz,filiale,retval);
}

static const char *bic_fkt_s(char *bic1,int mode,int filiale,int *retval,char **base,int error)
{
   const char *rv;
   int cnt,start_idx,ret1,ret2;

   if(!base){
      if(retval)*retval=error;
      return NULL;
   }
   if((ret1=bic_info(bic1,mode,&cnt,&start_idx))<0){
      if(retval)*retval=ret1;
      return NULL;
   }
   if(filiale>=cnt){
      if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
      return NULL;
   }
   rv=biq_fkt_s(start_idx+filiale,&ret2,base,error);
   if(retval){
      if(ret2<0)
         *retval=ret2;
      else
         *retval=ret1;
   }
   return rv;
}

static const char *biq_fkt_s(int idx,int *retval,char **base,int error)
{
   int ret;

   if(!base){
      if(retval)*retval=error;
      return NULL;
   }
   if(!idx){   /* Index 0 ist für Fehlerzustand reserviert */
      if(retval)*retval=INVALID_BIQ_INDEX;
      return NULL;
   }
   else if(idx>0)
      idx--;
   else
      idx++;

   if(idx>0){
      if(idx>lut2_cnt){  /* der Test ist nur sehr grob, aber es gibt an dieser Stelle nicht mehr Infos */
         if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
         return NULL;
      }
      if(!sort_bic_h){
         ret=lut_suche_bic_h("MARKDEF1100",NULL,NULL,NULL,NULL,NULL);  /* sort_bic_h initialisieren */
         if(ret<0){
            if(retval)*retval=ret;
            return NULL;
         }
      }
      if(retval)*retval=OK;
      return base[sort_bic_h[idx]];
   }
   else{
      idx=-idx;
      if(idx>lut2_cnt){
         if(retval)*retval=LUT2_INDEX_OUT_OF_RANGE;
         return NULL;
      }
      if(!sort_bic){
         ret=lut_suche_bic("MARKDEF1100",NULL,NULL,NULL,NULL,NULL);  /* sort_bic initialisieren */
         if(ret<0){
            if(retval)*retval=ret;
            return NULL;
         }
      }
      if(retval)*retval=OK;
      return base[sort_bic[idx]];
   }
}

static const char *iban_fkt_s(char *iban,int filiale,int *retval,const char*(*fkt)(char*,int,int*))
{
   char blz[9];

      /* nur zwei kleine Tests für die IBAN, dann die BLZ kopieren und die Funktion aufrufen */
   if((*iban!='d' && *iban!='D') || (iban[1]!='e' && iban[1]!='E')){
      if(retval)*retval= IBAN_ONLY_GERMAN;
      return NULL;
   }
   if(strlen(iban)!=22){
      if(retval)*retval=INVALID_IBAN_LENGTH;
      return NULL;
   }

   memcpy(blz,iban+4,8);
   *(blz+8)=0;
   return fkt(blz,filiale,retval);
}


/* Funktion kto_check_set_default() und kto_check_set_default_bin() +§§§1 */
/* ###########################################################################
 * # Diese Funktionen setzt einen Wert für den Default-Block der LUT-Datei.  #
 * # Der Block ist für Konfigurationsdaten von Anwenderprogrammen gedacht    #
 * # und soll vor allem auch ein Beispiel für die eigene Verwendung der      #
 * # LUT-Routinen sein. Als Schlüssel sind C-Strings zugelassen (also ohne   #
 * # eingebettete NULL-Bytes); für die Daten sind beliebige Werte erlaubt,   #
 * # inklusive NULL-Bytes; die Funktion set_default() erwartet hier jedoch   #
 * # auch einen C-String, benötigt dafür aber nicht den Längenparameter.     #
 * #                                                                         #
 * # Diese Funktion schreibt den Block nur in den internen Speicher; mit der #
 * # Funktion kto_check_write_default wird der Block in die LUT-Datei        #
 * # geschrieben.                                                            #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    key:        Schlüssel                                                #
 * #    val:        Daten                                                    #
 * #    size:   Größe des Datenblocks (nur bei set_default_bin() )           #
 * #                                                                         #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_set_default(char *key,char *val)
{
   return kto_check_set_default_bin(key,val,strlen(val)+1);
}

DLL_EXPORT int kto_check_set_default_bin(char *key,char *val,int size)
{
   char *ptr;
   int i,j,ret;
   unsigned long offset_k[DEFAULT_CNT],offset_v[DEFAULT_CNT];

   if(!default_buffer && (ret=kto_check_clear_default())!=OK)RETURN(ret); /* u.U. Initialisierung */
   if(((unsigned long)(default_ptr-default_buffer))<(unsigned long)size+strlen(key)+1){   /* realloc notwendig */
      for(i=0;i<default_cnt;i++){
         offset_k[i]=default_key[i]-default_buffer;
         offset_v[i]=default_val[i]-default_buffer;
      }
      if(!(ptr=(char *)realloc(default_buffer,default_bufsize+INITIAL_DEFAULT_BUFSIZE)))return ERROR_MALLOC;
      default_bufsize+=INITIAL_DEFAULT_BUFSIZE;
      default_buffer=ptr;
      for(i=0;i<default_cnt;i++){
         default_key[i]=default_buffer+offset_k[i];
         default_val[i]=default_buffer+offset_v[i];
      }
   }
   for(j=0;j<default_cnt;j++)if(!strcmp(key,default_key[j]))break;   /* Schlüssel suchen */

      /* zu viele Schlüssel angefordert; Abhilfe nur durch Neukompilieren mit
       * größerem Wert für DEFAULT_CNT. An sich ließe sich der Wert auch
       * dynamisch erhöhen, es ist nur die Frage, ob sich der Aufwand lohnt
       * (der Block ist ja nur für Programmeinstellungen o.ä. gedacht, nicht
       * als Universallösung für alles :-) ).
       */
   if(j==DEFAULT_CNT)return KTO_CHECK_DEFAULT_BLOCK_FULL;
   if(j==default_cnt){
      ret=OK;
      default_cnt++;    /* neuer Schlüssel */
      for(ptr=key,default_key[j]=default_ptr;(*default_ptr++=*ptr++););
   }
   else
      ret=KTO_CHECK_VALUE_REPLACED;
   for(i=0,default_val[j]=default_ptr,ptr=val;i<size;i++)*default_ptr++=*ptr++;
   *default_ptr++=0;    /* Abgrenzung, nur zur Sicherheit */
   default_val_size[j]=size;
   RETURN(ret);
}

/* Funktion kto_check_clear_default() +§§§1 */
/* ###########################################################################
 * # Diese Funktion initialisiert die Variablen für den Default-Block und    #
 * # löscht evl. vorhandene Werte.                                           #
 * #                                                                         #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int kto_check_clear_default(void)
{
   int i;

   if(!default_buffer){ /* muß noch Speicher für den buffer allokieren */
      if(!(default_buffer=(char *)calloc(INITIAL_DEFAULT_BUFSIZE,1))){
         default_buffer=NULL;
         return ERROR_MALLOC;
      }
      default_bufsize=INITIAL_DEFAULT_BUFSIZE;
   }
   default_cnt=0;
   default_ptr=default_buffer;
   for(i=0;i<DEFAULT_CNT;i++){
      default_key[i]=default_val[i]=NULL;
      default_val_size[i]=0;
   }
   return OK;
}

/* Funktion kto_check_init_default() +§§§1 */
/* ###########################################################################
 * # Diese Funktion liest den Default-Block der LUT-Datei und initialisiert  #
 * # die internen Variablen. Falls für block_id der Wert 0 übergeben wird,   #
 * # wird LUT2_DEFAULT benutzt. Durch Angabe eines anderen Wertes lassen     #
 * # sich mehrere Default-Blocks (mit unterschiedlichen IDs) in einer LUT-   #
 * # Datei unterbringen.                                                     #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    lut_name:   Name der LUT-Datei                                       #
 * #    block_id:   ID in der LUT-Datei für den Block                        #
 * #                                                                         #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_init_default(char *lut_name,int block_id)
{
   UINT4 blocklen;
   char *ptr,*data,name_buffer[LUT_PATH_LEN];
   const char *ptr1;
   int ret,i,j,k;
   struct stat s_buf;

      /* falls keine LUT-Datei angegeben wurde, die Suchpfade und Defaultnamen durchprobieren */
   if(!lut_name || !*lut_name){
      for(j=0,k=-1;j<lut_searchpath_cnt && k==-1;j++){
         for(i=0,lut_name=name_buffer;i<lut_name_cnt;i++){
#if _WIN32>0
            snprintf(lut_name,LUT_PATH_LEN,"%s\\%s",lut_searchpath[j],default_lutname[i]);
#else
            snprintf(lut_name,LUT_PATH_LEN,"%s/%s",lut_searchpath[j],default_lutname[i]);
#endif
            if(!(k=stat(lut_name,&s_buf)))break;
         }
      }
      if(k==-1)return NO_LUT_FILE;  /* keine Datei gefunden */
   }

      /* Variablen initialisieren */
   if((ret=kto_check_clear_default())!=OK)RETURN(ret);

      /* Default-Block lesen */
   if(!block_id)block_id=LUT2_DEFAULT;
   if((ret=read_lut_block(lut_name,block_id,&blocklen,&data))!=OK)RETURN(ret);
   if(default_bufsize<(int)blocklen){
      if(!(ptr=(char *)realloc(default_buffer,default_bufsize+INITIAL_DEFAULT_BUFSIZE)))
         return ERROR_MALLOC;
      else
         default_buffer=ptr;
   }
   for(ptr=data,ptr1="Default Block";*ptr1;)if(*ptr++!=*ptr1++)return KTO_CHECK_DEFAULT_BLOCK_INVALID;
   ptr++;
   C2UL(default_cnt,ptr);
   if(default_cnt>DEFAULT_CNT)return KTO_CHECK_DEFAULT_BLOCK_INVALID;
   for(i=0;i<default_cnt;i++)C2UL(default_val_size[i],ptr);
   for(ptr1="Default Block Namen";*ptr1;)if(*ptr++!=*ptr1++)return KTO_CHECK_DEFAULT_BLOCK_INVALID;
   ptr++;
   for(i=0,default_ptr=default_buffer;i<default_cnt;){
      default_key[i++]=default_ptr;
      while((*default_ptr++=*ptr++));
   }
   for(ptr1="Default Block Daten";*ptr1;)if(*ptr++!=*ptr1++)return KTO_CHECK_DEFAULT_BLOCK_INVALID;
   ptr++;
   for(i=0;i<default_cnt;i++){
      default_val[i]=default_ptr;
      for(j=0;j<default_val_size[i];j++)*default_ptr++=*ptr++;
   }
   free(data);
   return OK;
}

/* Funktion kto_check_get_default() +§§§1 */
/* ###########################################################################
 * # Diese Funktion sucht nach dem angegebenen Schlüssel und liefert den mit #
 * # diesem Schlüssel assoziierten Wert zurück. Es dabei wird vorausgesetzt, #
 * # daß die internen Variablen mit der Funktion kto_check_init_default()    #
 * # initialisiert wurde. Die Variable val wird auf den internen Pointer     #
 * # gesetzt, daher darf der übergebene Wert nicht verändert werden. Die     #
 * # Funktion allokiert keinen neuen Speicher.                               #
 * #                                                                         #
 * # Falls der angegebene Schlüssel nicht gefunden wurde, wird die           #
 * # Fehlermeldung KTO_CHECK_KEY_NOT_FOUND zurückgegeben und val auf einen   #
 * # Leerstring gesetzt; falls die LUT-Datei keinen Defaultblock enthält,    #
 * # ist das Funktionsergebnis LUT2_BLOCK_NOT_IN_FILE.                       #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    key:        Schlüssel                                                #
 * #    val:        Wert (Rückgabe per Referenz)                             #
 * #    size:       Größe des Datenblocks (per Referenz)                     #
 * #                                                                         #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_get_default(char *key,char **val,int *size)
{
   int i;

   for(i=0;i<default_cnt;i++)if(!strcmp(key,default_key[i]))break;
   if(i==default_cnt){
      *val=NULL;
      *size=0;
      return KTO_CHECK_KEY_NOT_FOUND;
   }
   *val=default_val[i];
   *size=default_val_size[i];
   return OK;
}

/* Funktion kto_check_default_keys() +§§§1 */
/* ###########################################################################
 * # Diese Funktion gibt die aktuellen Schlüssel des Default-Blocks zurück.  #
 * # Dabei wird vorausgesetzt, daß der Block bereits initialisiert ist       #
 * # (durch kto_check_init_default() oder kto_check_set_default() ). Es wird #
 * # nur ein Pointer auf das interne Array zurückgegeben, daher dürfen die   #
 * # Werte nicht verändert werden. Die Funktion allokiert keinen neuen       #
 * # Speicher.                                                               #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    keys:       Array mit den Schlüsseln (Rückgabe per Referenz)         #
 * #    cnt:        Anzahl (Rückgabe per Referenz)                           #
 * #                                                                         #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_default_keys(char ***keys,int *cnt)
{
   if(!default_buffer)return KTO_CHECK_NO_DEFAULT_BLOCK;
   *cnt=default_cnt;
   *keys=default_key;
   return OK;
}

/* Funktion kto_check_write_default() +§§§1 */
/* ###########################################################################
 * # Diese Funktion schreibt den Default-Block in eine LUT-Datei. Der Block  #
 * # muß vorher mittels der Funktion kto_check_set_default() gefüllt werden; #
 * # ansonsten wird die Fehlermeldung KTO_CHECK_NO_DEFAULT_BLOCK             #
 * # zurückgegeben.                                                          #
 * #                                                                         #
 * # block_id ist die (interne) ID in der LUT-Datei. Falls 0 übergeben wird, #
 * # wird LUT2_DEFAULT benutzt. Durch Angabe eines anderen Wertes lassen     #
 * # sich mehrere Default-Blocks (mit unterschiedlichen IDs) in einer LUT-   #
 * # Datei unterbringen.                                                     #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    lutfile:    LUT-Datei in die der Block geschrieben werden soll       #
 * #    block_id:   ID in der LUT-Datei für den Block                        #
 * #                                                                         #
 * # Copyright (C) 2010 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_write_default(char *lutfile,int block_id)
{
   char *buffer,*dptr;
   const char *ptr;
   int i,j,ret;

   if(!(buffer=(char *)calloc(default_bufsize+default_cnt*4+58,1)))return ERROR_MALLOC;
   for(ptr="Default Block",dptr=buffer;(*dptr++=*ptr++););  /* Signatur Block gesamt */
   UL2C(default_cnt,dptr);
   for(i=0;i<default_cnt;i++)UL2C(default_val_size[i],dptr);
   for(ptr="Default Block Namen";(*dptr++=*ptr++););  /* Signatur Blocknamen */
   for(i=0;i<default_cnt;i++)for(ptr=default_key[i];(*dptr++=*ptr++););
   for(ptr="Default Block Daten";(*dptr++=*ptr++););  /* Signatur Blockdaten */
   for(i=0;i<default_cnt;i++)for(ptr=default_val[i],j=0;j++<default_val_size[i];*dptr++=*ptr++);
   if(!block_id)block_id=LUT2_DEFAULT;
   ret=write_lut_block(lutfile,block_id,(dptr-buffer+1),buffer);
   free(buffer);
   return ret;
}

/* Funktion kto_check_encoding() +§§§1 */
/* ###########################################################################
 * # Diese Funktion setzt die Kodierung für die konto_check Bibliothek fest. #
 * # Es wird sowohl die Kodierung für die Fehlermeldungen als auch die der   #
 * # LUT-Datei gesetzt. Innerhalb der LUT-Datei sind die Werte im Format     #
 * # ISO-8859-1 gespeichert; sie werden bei der Initialisierung konvertiert. #
 * #                                                                         #
 * # Für den Parameter mode werden die folgenden Werte akzeptiert:           #
 * #     1,'i','I':  ISO-8859-1                                              #
 * #     2,'u','U':  UTF-8                                                   #
 * #     3,'h','H':  HTML-Entities                                           #
 * #     4,'d','D':  DOS (CP850)                                             #
 * #     51          Fehlermeldungen als Makronamen, Rest in ISO-8859-1      #
 * #     52          Fehlermeldungen als Makronamen, Rest in UTF-8           #
 * #     53          Fehlermeldungen als Makronamen, Rest in HTML-Entities   #
 * #     54          Fehlermeldungen als Makronamen, Rest in DOS (CP850)     #
 * #                                                                         #
 * # Rückgabewert ist der aktuell gesetzte Modus (als Zahl). Falls die       #
 * # Funktion mit dem Parameter 0 aufgerufen wird, wird nur die aktuelle     #
 * # Kodierung zurückgegeben.                                                #
 * #                                                                         #
 * # Copyright (C) 2011 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kto_check_encoding(int mode)
{
   char *ptr,*data,*eptr,*hs=NULL;
   int lut_encoding,i,retval;
   UINT4 len;

   lut_encoding=encoding%10;
   switch(mode){
      case 0:
         return current_encoding;

      case 1:
      case 'i':
      case 'I':
         encoding=1;
         current_encoding=current_encoding%10+10;
         retval_enc=kto_check_retval2iso;
         break;

      case 2:
      case 'u':
      case 'U':
         encoding=2;
         current_encoding=current_encoding%10+20;
         retval_enc=kto_check_retval2utf8;
         break;

      case 3:
      case 'h':
      case 'H':
         encoding=3;
         current_encoding=current_encoding%10+30;
         retval_enc=kto_check_retval2html;
         break;

      case 4:
      case 'd':
      case 'D':
         encoding=4;
         current_encoding=current_encoding%10+40;
         retval_enc=kto_check_retval2dos;
         break;

      case 'm':
      case 'M':
      case 51:
         encoding=51;
         current_encoding=current_encoding%10+50;
         retval_enc=kto_check_retval2txt_short;
         break;

      case 52:
         encoding=52;
         current_encoding=current_encoding%10+50;
         retval_enc=kto_check_retval2txt_short;
         break;

      case 53:
         encoding=53;
         current_encoding=current_encoding%10+50;
         retval_enc=kto_check_retval2txt_short;
         break;

      case 54:
         encoding=54;
         current_encoding=current_encoding%10+50;
         retval_enc=kto_check_retval2txt_short;
         break;
   }
   if(keep_raw_data_flag && lut_encoding!=encoding%10){ /* falls notwendig, die LUT-Blocks neu kodieren */
      if(name_raw && name_data){

            /* bei alter Kodierung mit ISO 8859-1 (d.h. name_raw==name_data)
             * name_data nicht freigeben, sonst sind auch die raw Daten weg!!!
             */
         if(name_raw!=name_data)FREE(name_data);
         FREE(sort_name);  /* Sortierarray freigeben */
         name_data=name_raw;
         len=name_raw_len;
         data=name_raw;
         if((retval=convert_encoding(&data,&len))<=0)return retval;
         for(i=0,name_data=ptr=data,eptr=data+len;ptr<eptr && i<lut2_cnt;i++){
            if(*ptr==1)
               hs=name[i]=++ptr;
            else if(*ptr)
               name[i]=ptr;
            else
               name[i]=hs;
            while(*ptr++ && ptr<eptr);
         }
      }
      if(name_kurz_raw && name_kurz_data){
         if(name_kurz_raw!=name_kurz_data)FREE(name_kurz_data);
         FREE(sort_name_kurz);
         name_kurz_data=name_kurz_raw;
         len=name_kurz_raw_len;
         data=name_kurz_raw;
         if((retval=convert_encoding(&data,&len))<=0)return retval;
         for(i=0,name_kurz_data=ptr=data,eptr=data+len;ptr<eptr && i<lut2_cnt;i++){
            name_kurz[i]=ptr;
            while(*ptr++ && ptr<eptr);
         }
      }
      if(name_name_kurz_raw && name_name_kurz_data){
         if(name_name_kurz_raw!=name_name_kurz_data)FREE(name_name_kurz_data);
         FREE(sort_name);
         FREE(sort_name_kurz);
         name_name_kurz_data=name_name_kurz_raw;
         len=name_name_kurz_raw_len;
         data=name_name_kurz_raw;
         if((retval=convert_encoding(&data,&len))<=0)return retval;
         for(i=0,name_name_kurz_data=ptr=data,eptr=data+len;ptr<eptr && i<lut2_cnt;i++){
            if(*ptr==1)
               hs=name[i]=++ptr;
            else if(*ptr)
               name[i]=ptr;
            else
               name[i]=hs;
            while(ptr<eptr && *ptr++);
            name_kurz[i]=ptr;
            while(ptr<eptr && *ptr++);
         }
      }
      if(ort_raw && ort_data){
         if(ort_raw!=ort_data)FREE(ort_data);
         FREE(sort_ort);
         ort_data=ort_raw;
         len=ort_raw_len;
         data=ort_raw;
         if((retval=convert_encoding(&data,&len))<=0)return retval;
         for(i=0,ort_data=ptr=data,eptr=data+len;ptr<eptr && i<lut2_cnt;i++){
            ort[i]=ptr;
            while(*ptr++ && ptr<eptr);
         }
      }
   }
   if(current_encoding<50 && (current_encoding%10==current_encoding/10 || !(current_encoding%10)
         || (!name_data && !name_kurz_data && ! name_name_kurz_data && !ort_data)))
      current_encoding/=10;
   return current_encoding;
}

/* Funktion kto_check_encoding_str() +§§§1 */
/* ###########################################################################
 * # Diese Funktion entspricht der Funktion kto_check_encoding(); allerdings #
 * # ist der Rückgabewert nicht numerisch, sondern ein String.               #
 * #                                                                         #
 * # Copyright (C) 2011 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT const char *kto_check_encoding_str(int mode)
{
   switch(kto_check_encoding(mode)){
      case 0:   return "noch nicht spezifiziert";

      case 1:
      case 11:  return "ISO-8859-1";
      case 2:
      case 22:  return "UTF-8";
      case 3:
      case 33:  return "HTML entities";
      case 4:
      case 44:  return "DOS CP-850";

      case 21:  return "UTF-8/ISO-8859-1";
      case 31:  return "HTML entities/ISO-8859-1";
      case 41:  return "DOS CP-850/ISO-8859-1";

      case 12:  return "ISO-8859-1/UTF-8";
      case 32:  return "HTML entities/UTF-8";
      case 42:  return "DOS CP-850/UTF-8";

      case 13:  return "ISO-8859-1/HTML";
      case 23:  return "UTF-8/HTML";
      case 43:  return "DOS CP-850/HTML";

      case 14:  return "ISO-8859-1/DOS CP 850";
      case 24:  return "UTF-8/DOS CP-850";
      case 34:  return "HTML entities/DOS CP-850";

      case 51: return "Makro/ISO-8859-1";
      case 52: return "Makro/UTF-8";
      case 53: return "Makro/HTML";
      case 54: return "Makro/DOS CP-850";

      default: return "Unbekannte Kodierung";
   }
}

/* Funktion keep_raw_data() +§§§1 */
/* ###########################################################################
 * # Diese Funktion setzt oder löscht das Flag keep_raw_data_flag. Das Flag  #
 * # legt fest, ob die raw-Daten der Lut-Blocks Name, Kurzname und Ort      .#
 * # gespeichert werden sollen; falls ja, werden sie bei einem Wechsel der   #
 * # Kodierung auch umkodiert, falls nein, ist das nicht möglich. Die        #
 * # Speicherung der raw-Daten benötigt etwa 900 KB an Hauptspeicher. Einige #
 * # Anmerkungen zu dem Flag finden sich auch oben bei der Deklaration von   #
 * # current_encoding etc.                                                   #
 * #                                                                         #
 * # Mögliche Werte für den Funktionsparameter mode:                         #
 * #    1: Flag setzen                                                       #
 * #    0: Flag abfragen, nicht verändern                                    #
 * #   -1: Flag löschen, Speicher der raw-Daten freigeben                    #
 * #                                                                         #
 * # Copyright (C) 2011 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int keep_raw_data(int mode)
{
   if(mode==1)
      keep_raw_data_flag=1;
   else if(mode==-1){
         /* Speicher für die raw-Daten wieder freigeben */
      keep_raw_data_flag=0;
      if(name_raw!=name_data)
         FREE(name_raw);
      else
         name_raw=NULL;
      if(name_kurz_raw!=name_kurz_data)
         FREE(name_kurz_raw);
      else
         name_kurz_raw=NULL;
      if(name_name_kurz_raw!=name_name_kurz_data)
         FREE(name_name_kurz_raw);
      else
         name_name_kurz_raw=NULL;
      if(ort_raw!=ort_data)
         FREE(ort_raw);
      else
         ort_raw=NULL;
      name_raw_len=name_kurz_raw_len=name_name_kurz_raw_len=ort_raw_len=0;
   }
   return keep_raw_data_flag;
}

/* Funktion convert_encoding() +§§§1 */
/* ###########################################################################
 * # Diese Funktion konvertiert einen gelesenen LUT-Block in die gewünschte  #
 * # Kodierung. Der ursprünglich allokierte Speicher wird wieder freigegeben.#
 * #                                                                         #
 * # Copyright (C) 2011 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

static int convert_encoding(char **data,UINT4 *len)
{
   unsigned char *buffer,*sptr,*dptr,*ptr,*eptr1,*eptr2;
   int buflen,offset;

   buflen=*len;
   switch(encoding){
      case 1:
      case 51: /* ISO 8859-1 */
         current_encoding=(current_encoding/10)*10+1;
         break;

      case 2:  /* UTF-8 */
      case 52:
         if(!(buffer=(unsigned char *)malloc(buflen+=8192)))return ERROR_MALLOC;
         current_encoding=(current_encoding/10)*10+2;
         sptr=UCP *data;
         eptr1=sptr+*len;
         dptr=buffer;
         while(sptr<eptr1){
            for(eptr2=buffer+buflen-10;sptr<eptr1 && dptr<eptr2;sptr++)switch(*sptr){
               case 0xe4: *dptr++=0xc3; *dptr++=0xa4; break;    /* ä */ 
               case 0xc4: *dptr++=0xc3; *dptr++=0x84; break;    /* Ä */ 
               case 0xf6: *dptr++=0xc3; *dptr++=0xb6; break;    /* ö */ 
               case 0xd6: *dptr++=0xc3; *dptr++=0x96; break;    /* Ö */ 
               case 0xfc: *dptr++=0xc3; *dptr++=0xbc; break;    /* ü */ 
               case 0xdc: *dptr++=0xc3; *dptr++=0x9c; break;    /* Ü */ 
               case 0xdf: *dptr++=0xc3; *dptr++=0x9f; break;    /* ß */ 
               default:  *dptr++=*sptr;
            }
            if(sptr<eptr1){         /* es wird langsam eng; buffer vergrößern */
               offset=dptr-buffer;  /* die Buffer-Adresse verschiebt sich u.U.; dptr muß korrigiert werden */
               if(!(buffer=(unsigned char *)realloc(buffer,buflen+=4096)))return ERROR_MALLOC;
               dptr=buffer+offset;
            }
         }
         buffer=(unsigned char *)realloc(buffer,buflen=(dptr-buffer)+10);
         if(!keep_raw_data_flag)free(*data);   /* alte Daten, werden nicht mehr benötigt */
         *data=SCP buffer;
         *len=buflen;
         break;

      case 3:  /* HTML */
      case 53:
         if(!(buffer=(unsigned char *)malloc(buflen+=16384)))return ERROR_MALLOC;
         current_encoding=(current_encoding/10)*10+3;
         sptr=UCP *data;
         eptr1=sptr+*len;
         dptr=buffer;
         while(sptr<eptr1){
            for(eptr2=buffer+buflen-10;sptr<eptr1 && dptr<eptr2;sptr++)switch(*sptr){
               case 0xe4: for(ptr=UCP "&auml;"; *ptr;)*dptr++=*ptr++; break;    /* ä */
               case 0xc4: for(ptr=UCP "&Auml;"; *ptr;)*dptr++=*ptr++; break;    /* Ä */
               case 0xf6: for(ptr=UCP "&ouml;"; *ptr;)*dptr++=*ptr++; break;    /* ö */
               case 0xd6: for(ptr=UCP "&Ouml;"; *ptr;)*dptr++=*ptr++; break;    /* Ö */
               case 0xfc: for(ptr=UCP "&uuml;"; *ptr;)*dptr++=*ptr++; break;    /* ü */
               case 0xdc: for(ptr=UCP "&Uuml;"; *ptr;)*dptr++=*ptr++; break;    /* Ü */
               case 0xdf: for(ptr=UCP "&szlig;";*ptr;)*dptr++=*ptr++; break;    /* ß */
               default: *dptr++=*sptr;
            }
            if(sptr<eptr1){         /* es wird langsam eng; buffer vergrößern */
               offset=dptr-buffer;  /* die Buffer-Adresse verschiebt sich u.U.; dptr muß korrigiert werden */
               if(!(buffer=(unsigned char *)realloc(buffer,buflen+=8192)))return ERROR_MALLOC;
               dptr=buffer+offset;
            }
         }
         if(!keep_raw_data_flag)free(*data);   /* alte Daten, werden nicht mehr benötigt */
         *data=SCP buffer;
         *len=buflen;
         break;

      case 4:  /* DOS CP 850 */
      case 54:
         if(keep_raw_data_flag){   /* Daten kopieren, Kopie bearbeiten */
            if(!(buffer=(unsigned char *)malloc(buflen)))return ERROR_MALLOC;
            current_encoding=(current_encoding/10)*10+4;
            for(sptr=UCP *data,eptr1=sptr+*len,dptr=buffer;sptr<eptr1;sptr++,dptr++)switch(*sptr){
               case 0xe4: *dptr=0x84; break;    /* ä */
               case 0xc4: *dptr=0x8e; break;    /* Ä */
               case 0xf6: *dptr=0x94; break;    /* ö */
               case 0xd6: *dptr=0x99; break;    /* Ö */
               case 0xfc: *dptr=0x81; break;    /* ü */
               case 0xdc: *dptr=0x9a; break;    /* Ü */
               case 0xdf: *dptr=0xe1; break;    /* ß */
               default:   *dptr=*sptr;
            }
            *data=SCP buffer;
            *len=buflen;
         }
         else{ /* !keep_raw_data: die Daten direkt im buffer ändern */
            for(ptr=UCP *data,eptr1=ptr+*len;ptr<eptr1;ptr++)switch(*ptr){
               case 0xe4: *ptr=0x84; break;    /* ä */
               case 0xc4: *ptr=0x8e; break;    /* Ä */
               case 0xf6: *ptr=0x94; break;    /* ö */
               case 0xd6: *ptr=0x99; break;    /* Ö */
               case 0xfc: *ptr=0x81; break;    /* ü */
               case 0xdc: *ptr=0x9a; break;    /* Ü */
               case 0xdf: *ptr=0xe1; break;    /* ß */
            }
         }
         break;
      default:    /* nicht definierte Kodierung: nichts zu tun */
         break;
   }
   return OK;
}

DLL_EXPORT const char *pz2str(int pz,int *ret)
{
   if(ret){
      if(pz%1000>=142)
         *ret=NOT_DEFINED;
      else
         *ret=OK;
   }
   switch(pz){
      case   0: return "00";
      case   1: return "01";
      case   2: return "02";
      case   3: return "03";
      case   4: return "04";
      case   5: return "05";
      case   6: return "06";
      case   7: return "07";
      case   8: return "08";
      case   9: return "09";
      case  10: return "10";
      case  11: return "11";
      case  12: return "12";
      case  13: return "13";
      case  14: return "14";
      case  15: return "15";
      case  16: return "16";
      case  17: return "17";
      case  18: return "18";
      case  19: return "19";
      case  20: return "20";
      case  21: return "21";
      case  22: return "22";
      case  23: return "23";
      case  24: return "24";
      case  25: return "25";
      case  26: return "26";
      case  27: return "27";
      case  28: return "28";
      case  29: return "29";
      case  30: return "30";
      case  31: return "31";
      case  32: return "32";
      case  33: return "33";
      case  34: return "34";
      case  35: return "35";
      case  36: return "36";
      case  37: return "37";
      case  38: return "38";
      case  39: return "39";
      case  40: return "40";
      case  41: return "41";
      case  42: return "42";
      case  43: return "43";
      case  44: return "44";
      case  45: return "45";
      case  46: return "46";
      case  47: return "47";
      case  48: return "48";
      case  49: return "49";
      case  50: return "50";
      case  51: return "51";
      case  52: return "52";
      case  53: return "53";
      case  54: return "54";
      case  55: return "55";
      case  56: return "56";
      case  57: return "57";
      case  58: return "58";
      case  59: return "59";
      case  60: return "60";
      case  61: return "61";
      case  62: return "62";
      case  63: return "63";
      case  64: return "64";
      case  65: return "65";
      case  66: return "66";
      case  67: return "67";
      case  68: return "68";
      case  69: return "69";
      case  70: return "70";
      case  71: return "71";
      case  72: return "72";
      case  73: return "73";
      case  74: return "74";
      case  75: return "75";
      case  76: return "76";
      case  77: return "77";
      case  78: return "78";
      case  79: return "79";
      case  80: return "80";
      case  81: return "81";
      case  82: return "82";
      case  83: return "83";
      case  84: return "84";
      case  85: return "85";
      case  86: return "86";
      case  87: return "87";
      case  88: return "88";
      case  89: return "89";
      case  90: return "90";
      case  91: return "91";
      case  92: return "92";
      case  93: return "93";
      case  94: return "94";
      case  95: return "95";
      case  96: return "96";
      case  97: return "97";
      case  98: return "98";
      case  99: return "99";
      case 100: return "A0";
      case 101: return "A1";
      case 102: return "A2";
      case 103: return "A3";
      case 104: return "A4";
      case 105: return "A5";
      case 106: return "A6";
      case 107: return "A7";
      case 108: return "A8";
      case 109: return "A9";
      case 110: return "B0";
      case 111: return "B1";
      case 112: return "B2";
      case 113: return "B3";
      case 114: return "B4";
      case 115: return "B5";
      case 116: return "B6";
      case 117: return "B7";
      case 118: return "B8";
      case 119: return "B9";
      case 120: return "C0";
      case 121: return "C1";
      case 122: return "C2";
      case 123: return "C3";
      case 124: return "C4";
      case 125: return "C5";
      case 126: return "C6";
      case 127: return "C7";
      case 128: return "C8";
      case 129: return "C9";
      case 130: return "D0";
      case 131: return "D1";
      case 132: return "D2";
      case 133: return "D3";
      case 134: return "D4";
      case 135: return "D5";
      case 136: return "D6";
      case 137: return "D7";
      case 138: return "D8";
      case 139: return "D9";
      case 140: return "E0";
      case 141: return "E1";
      case 1013: return "13a";
      case 1049: return "49a";
      case 1050: return "50a";
      case 1051: return "51a";
      case 1052: return "52a";
      case 1053: return "53a";
      case 1057: return "57a";
      case 1061: return "61a";
      case 1063: return "63a";
      case 1066: return "66a";
      case 1068: return "68a";
      case 1069: return "69a";
      case 1073: return "73a";
      case 1074: return "74a";
      case 1075: return "75a";
      case 1076: return "76a";
      case 1077: return "77a";
      case 1080: return "80a";
      case 1081: return "81a";
      case 1082: return "82a";
      case 1083: return "83a";
      case 1084: return "84a";
      case 1085: return "85a";
      case 1086: return "86a";
      case 1087: return "87a";
      case 1089: return "89a";
      case 1090: return "90a";
      case 1091: return "91a";
      case 1093: return "93a";
      case 1096: return "96a";
      case 1098: return "98a";
      case 1102: return "A2a";
      case 1103: return "A3a";
      case 1104: return "A4a";
      case 1105: return "A5a";
      case 1106: return "A6a";
      case 1107: return "A7a";
      case 1108: return "A8a";
      case 1109: return "A9a";
      case 1110: return "B0a";
      case 1111: return "B1a";
      case 1112: return "B2a";
      case 1113: return "B3a";
      case 1114: return "B4a";
      case 1115: return "B5a";
      case 1116: return "B6a";
      case 1117: return "B7a";
      case 1118: return "B8a";
      case 1119: return "B9a";
      case 1120: return "C0a";
      case 1121: return "C1a";
      case 1122: return "C2a";
      case 1123: return "C3a";
      case 1124: return "C4a";
      case 1125: return "C5a";
      case 1127: return "C7a";
      case 1128: return "C8a";
      case 1129: return "C9a";
      case 1130: return "D0a";
      case 1132: return "D2a";
      case 1133: return "D3a";
      case 1135: return "D5a";
      case 1136: return "D6a";
      case 1138: return "D8a";
      case 1139: return "D9a";
      case 2013: return "13b";
      case 2049: return "49b";
      case 2050: return "50b";
      case 2051: return "51b";
      case 2052: return "52b";
      case 2053: return "53b";
      case 2057: return "57b";
      case 2061: return "61b";
      case 2063: return "63b";
      case 2066: return "66b";
      case 2068: return "68b";
      case 2069: return "69b";
      case 2073: return "73b";
      case 2074: return "74b";
      case 2075: return "75b";
      case 2076: return "76b";
      case 2077: return "77b";
      case 2080: return "80b";
      case 2081: return "81b";
      case 2082: return "82b";
      case 2083: return "83b";
      case 2084: return "84b";
      case 2085: return "85b";
      case 2086: return "86b";
      case 2087: return "87b";
      case 2089: return "89b";
      case 2090: return "90b";
      case 2091: return "91b";
      case 2093: return "93b";
      case 2096: return "96b";
      case 2098: return "98b";
      case 2102: return "A2b";
      case 2103: return "A3b";
      case 2104: return "A4b";
      case 2105: return "A5b";
      case 2106: return "A6b";
      case 2107: return "A7b";
      case 2108: return "A8b";
      case 2109: return "A9b";
      case 2110: return "B0b";
      case 2111: return "B1b";
      case 2112: return "B2b";
      case 2113: return "B3b";
      case 2114: return "B4b";
      case 2115: return "B5b";
      case 2116: return "B6b";
      case 2117: return "B7b";
      case 2118: return "B8b";
      case 2119: return "B9b";
      case 2120: return "C0b";
      case 2121: return "C1b";
      case 2122: return "C2b";
      case 2123: return "C3b";
      case 2124: return "C4b";
      case 2125: return "C5b";
      case 2127: return "C7b";
      case 2128: return "C8b";
      case 2129: return "C9b";
      case 2130: return "D0b";
      case 2132: return "D2b";
      case 2133: return "D3b";
      case 2135: return "D5b";
      case 2136: return "D6b";
      case 2138: return "D8b";
      case 2139: return "D9b";
      case 3051: return "51c";
      case 3057: return "57c";
      case 3068: return "68c";
      case 3073: return "73c";
      case 3075: return "75c";
      case 3080: return "80c";
      case 3081: return "81c";
      case 3083: return "83c";
      case 3084: return "84c";
      case 3085: return "85c";
      case 3086: return "86c";
      case 3087: return "87c";
      case 3089: return "89c";
      case 3090: return "90c";
      case 3091: return "91c";
      case 3093: return "93c";
      case 3096: return "96c";
      case 3104: return "A4c";
      case 3108: return "A8c";
      case 3118: return "B8c";
      case 3125: return "C5c";
      case 3127: return "C7c";
      case 3128: return "C8c";
      case 3132: return "D2c";
      case 3135: return "D5c";
      case 3136: return "D6c";
      case 3139: return "D9c";
      case 4051: return "51d";
      case 4057: return "57d";
      case 4073: return "73d";
      case 4080: return "80d";
      case 4083: return "83d";
      case 4084: return "84d";
      case 4085: return "85d";
      case 4086: return "86d";
      case 4087: return "87d";
      case 4090: return "90d";
      case 4091: return "91d";
      case 4093: return "93d";
      case 4104: return "A4d";
      case 4108: return "A8d";
      case 4125: return "C5d";
      case 4135: return "D5d";
      case 5051: return "51e";
      case 5073: return "73e";
      case 5084: return "84e";
      case 5087: return "87e";
      case 5090: return "90e";
      case 5104: return "A4e";
      case 6051: return "51f";
      case 6090: return "90f";
      case 7090: return "90g";
      default:   return "???";
   }
}

/* Funktion lut_keine_iban_berechnung() +§§§1 */
/*
 * ############################################################################
 * # Die Funktion lut_keine_iban_berechnung() konvertiert die Liste der       #  
 * # Banken, die einer IBAN-Berechnung nicht zugestimmt haben in das interne  #
 * # Format für konto_check. Als Eingabedatei wird die Datei CONFIG.INI des   #
 * # SEPA Account Converters der Sparkassen benutzt, die Ausgabe wird direkt  #
 * # als Block in die LUT-Datei geschrieben. Der Block wird automatisch beim  #
 * # Initialisieren eingelesen und von der Funktion iban_gen() ausgewertet.   #
 * #                                                                          #
 * # Hier ein Auszug aus der Anleitung des SEPA Account Converters:           #
 * #                                                                          #
 * # Der SEPA Account Converter ist so eingestellt, dass nur                  #
 * # Kontoverbindungen in IBAN und BIC umgerechnet werden, bei denen das      #
 * # ausgebende Kreditinstitut der Umrechnung zugestimmt hat.                 #
 * # Kreditinstitute, welche einer Umrechnung nicht zugestimmt haben und      #
 * # welche zum Teil spezielle, dem SEPA Account Converter nicht bekannte     #
 * # Umrechnungsmethoden verwenden, sind in der Datei "CONFIG.INI"            #
 * # hinterlegt. Durch Löschen der Datei "CONFIG.INI" aus dem                 #
 * # Programmverzeichnis haben Sie die Möglichkeit, eine Umrechnung für alle  #
 * # Konten durchzuführen. Bitte beachten Sie dabei, dass die so erhaltenen   #
 * # IBAN und BIC fehlerhaft sein können und deshalb mit ihren Kunden zu      #
 * # überprüfen sind.                                                         #
 * ############################################################################
 */ 

/* Weblinks:
 * https://www.sparkasse-rhein-neckar-nord.de/pdf/content/sepa/kurzanleitung.pdf
 * https://www.sparkasse-rhein-neckar-nord.de/firmenkunden/internationales_geschaeft/sepa/vorteile/index.php
 * https://www.sparkasse-rhein-neckar-nord.de/firmenkunden/internationales_geschaeft/sepa/vorteile/sepa_account_converter.msi
 * http://www.sfirm.de/update/prgupd.htm
 */

DLL_EXPORT int lut_keine_iban_berechnung(char *iban_blacklist,char *lutfile,int set)
{
   char *ptr,*ptr1,*dptr,*dptr1,*sptr,*buffer,line[1024];
   int *ibuffer,i,size,retval,fertig=0,bufsize;
   UINT4 cnt;
   FILE *in,*lut;
   struct stat sbuf;


   if(stat(iban_blacklist,&sbuf))return FILE_READ_ERROR;
   if(!(in=fopen(iban_blacklist,"r")))return FILE_READ_ERROR;
   if(!(lut=fopen(lutfile,"rb+")))return FILE_WRITE_ERROR;
   size=sbuf.st_size;

      /* grobe Abschätzung für die Größe des benötigten Arrays: jede BLZ
       * benötigt 8 Byte. Der Wert size/8 ist etwas zu hoch, aber auf keinen
       * Fall zu klein. Da das Array nur zum Sortieren benötigt und gleich
       * wieder freigegeben wird, ist das egal.
       */
   if(!(ibuffer=(int *)calloc(size/8,sizeof(int))))return ERROR_MALLOC;

      /* die Daten einlesen */
   for(cnt=0;!feof(in);){
      if(!fgets(line,1024,in))break;
      if(!isdigit(*line))continue;  /* Kommentarzeilen etc. */
      for(ptr=line,i=0;i<8 && isdigit(*ptr);i++,ptr++);
      if(i<8 && strncmp(line,"2718281",7))continue;  /* eine BLZ muß 8 Ziffern enthalten (Sonderfall: Marker 2718281 */
      if(*ptr=='=' && *(ptr+1)=='0')   /* Dateiformat: <BLZ>=0 */
         *ptr=0;
      else
         continue;
      ibuffer[cnt++]=atoi(line);
   }
   qsort(ibuffer,cnt,sizeof(int),cmp_int);
   if(!(ptr=buffer=(char *)calloc(cnt+10,sizeof(int))))return ERROR_MALLOC;
   bufsize=(cnt+10)*sizeof(int);

      /* nun den Block in die LUT-Datei schreiben: zuerst die Anzahl, dann die BLZs */
   UL2C(cnt,ptr);
   for(i=0;i<(int)cnt;i++)UL2C(ibuffer[i],ptr);

   if(set==2)
      set_offset=SET_OFFSET;
   else
      set_offset=0;
   retval=write_lut_block_int(lut,LUT2_OWN_IBAN+set_offset,ptr-buffer,buffer);
   fflush(lut);

      /* Info-Block holen und Blockliste aktualisieren (falls noch nicht geschehen) */
   if(read_lut_block_int(lut,0,LUT2_INFO+set_offset,&cnt,&sptr)>0){
      if(bufsize<(int)cnt+16 && !(buffer=(char *)realloc(buffer,cnt+16)))return ERROR_MALLOC;  /* buffer u.U. vergrößern */
      for(fertig=i=0,ptr=sptr,dptr=buffer;i<(int)cnt && !fertig;){
         for(dptr1=dptr;*ptr!='\n' && i<(int)cnt && !fertig;i++)*dptr++=*ptr++; /* eine Zeile holen */
         *dptr=0;
         if(*ptr=='\n')ptr++;
         if(!strncmp(dptr1,"Enthaltene Felder:",18)){
            if(!strcmp(dptr-10,", OWN_IBAN")){
               fertig=1;   /* Block ist schon eingetragen, nicht ersetzen */
               break;
            }
            else
               for(ptr1=(char*)", OWN_IBAN";(*dptr=*ptr1++);dptr++);
         }
         *dptr++='\n';
         i++;
      }
      free(sptr);
   }
      /* der Block wurde um 10 Byte vergrößert, daher cnt+10 Byte schreiben */
   if(!fertig)write_lut_block_int(lut,LUT2_INFO+set_offset,cnt+10,buffer);
   fclose(in);
   fclose(lut);
   free(buffer);
   free(ibuffer);
   return retval;
}

/* Funktion pz_aenderungen_enable() +§§§1 */
/* ###########################################################################
 * # Die Funktion pz_aenderungen_enable() dient dazu, den Status des Flags   #
 * # pz_aenderungen_aktivieren abzufragen bzw. zu setzen. Falls die Variable #
 * # set 1 ist, werden die Änderungen aktiviert, falls sie 0 ist, werden     #
 * # die Änderungen deaktiviert. Bei allen anderen Werten wird das aktuelle  #
 * # Flag nicht verändert, sondern nur der Status zurückgegeben.             #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    set:        0 oder 1: Änderungen deaktivieren/aktivieren             #
 * #                anderer Wert: nur Abfrage des Status                     #
 * # Rückgabe:      aktueller Status des Flags                               #                                                               #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int pz_aenderungen_enable(int set)
{
   if(set==0 || set==1)pz_aenderungen_aktivieren=set;
   return pz_aenderungen_aktivieren;
}

#if DEBUG>0
/* Funktion kto_check_test_vars() +§§§1 */
/* ###########################################################################
 * # Die Funktion kto_check_test_vars() macht nichts anderes, als die beiden #
 * # übergebenen Variablen txt und i auszugeben und als String zurückzugeben.#
 * # Sie kann für Debugzwecke benutzt werden, wenn Probleme mit Variablen in #
 * # der DLL auftreten; ansonsten ist sie nicht allzu nützlich. Sie ist      #
 * # allerdings nicht threadfest, da sie mit *einem* statischem Buffer für   #
 * # die Ausgabe arbeitet ;-).                                               #
 * #                                                                         #
 * # Parameter:                                                              #
 * #    txt:        Textvariable                                             #
 * #    i:          Integervariable (4 Byte)                                 #
 * #                                                                         #
 * # Copyright (C) 2006 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT char *kto_check_test_vars(char *txt,UINT4 i)
{
   static char test_buffer[200];

   snprintf(test_buffer,200,"Textvariable: %s, Integervariable: %d (Hexwert: 0x%08X)\n",txt,i,i);
   return test_buffer;
}

#endif


/* Funktionen *_id() +§§§1 */
/* ###########################################################################
 * # Die folgenden Funktionen sind die id-Varianten von Funktionen, die      #
 * # normalerweise einen (konstanten) String zurückgeben; über diese Hilfs-  #
 * # funktionen wird stattdessen eine ID generiert und zurückgegeben. Bei    #
 * # Stringkonstanten wird für den entsprechenden id-Slot kein Speicher      #
 * # allokiert, sondern der Pointer wird direkt auf den String gesetzt. Auch #
 * # beim Aufruf von kc_id_free() wird für den Speicherblock nicht free()    #
 * # aufgerufen, sondern einfach nur der Slot freigegeben.                   #
 * #                                                                         #
 * # Da der Aufruf für jede Funktionsgruppe gleich ist, wird er per Makro    #
 * # gemacht.                                                                #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */
   /* numerische Rückgabewerte in eine id umwandeln */
#define RV_ID(fkt) \
DLL_EXPORT int kto_check_retval2 ## fkt ## _id(int retval)\
{\
   int handle,rv;\
\
   rv=kc_ptr2id((char*)kto_check_retval2 ## fkt(retval),&handle,0);\
   if(rv<0)\
      return -1;\
   else\
      return handle;\
}

RV_ID(txt)
RV_ID(txt_short)
RV_ID(html)
RV_ID(utf8)
RV_ID(dos)

   /* lut_*() und iban_*() Funktionen */
#define LUT_ID(fkt) \
DLL_EXPORT int fkt ## _id(char *b,int zweigstelle,int *retval)\
{\
   int handle,rv;\
\
   rv=kc_ptr2id((char*)fkt(b,zweigstelle,retval),&handle,0);\
   if(rv<0)\
      return -1;\
   else\
      return handle;\
}

LUT_ID(lut_name);
LUT_ID(lut_name_kurz);
LUT_ID(lut_ort);
LUT_ID(lut_bic);
LUT_ID(lut_bic_h);
LUT_ID(iban_bic);
LUT_ID(iban_bic_h);
LUT_ID(iban_name);
LUT_ID(iban_name_kurz);
LUT_ID(iban_ort);

#define LUT_I_ID(fkt) \
DLL_EXPORT int fkt ## _id(int b,int zweigstelle,int *retval)\
{\
   int handle,rv;\
\
   rv=kc_ptr2id((char*)fkt(b,zweigstelle,retval),&handle,0);\
   if(rv<0)\
      return -1;\
   else\
      return handle;\
}

LUT_I_ID(lut_bic_hi);
LUT_I_ID(lut_name_i);
LUT_I_ID(lut_name_kurz_i);
LUT_I_ID(lut_ort_i);
LUT_I_ID(lut_bic_i);

#define BIC_ID(fkt) \
DLL_EXPORT int fkt ## _id(char *b,int mode,int zweigstelle,int *retval)\
{\
   int handle,rv;\
\
   rv=kc_ptr2id((char*)fkt(b,mode,zweigstelle,retval),&handle,0);\
   if(rv<0)\
      return -1;\
   else\
      return handle;\
}

BIC_ID(bic_bic);
BIC_ID(bic_bic_h);
BIC_ID(bic_name);
BIC_ID(bic_name_kurz);
BIC_ID(bic_ort);

#define BIQ_ID(fkt) \
DLL_EXPORT int fkt ## _id(int idx,int *retval)\
{\
   int handle,rv;\
\
   rv=kc_ptr2id((char*)fkt(idx,retval),&handle,0);\
   if(rv<0)\
      return -1;\
   else\
      return handle;\
}

BIQ_ID(biq_bic);
BIQ_ID(biq_bic_h);
BIQ_ID(biq_name);
BIQ_ID(biq_name_kurz);
BIQ_ID(biq_ort);

DLL_EXPORT int kto_check_encoding_str_id(int mode)
{
   int handle,rv;

   rv=kc_ptr2id((char*)kto_check_encoding_str(mode),&handle,0);
   if(rv<0)
      return -1;
   else
      return handle;
}

DLL_EXPORT int get_kto_check_version_id(int mode)
{
   int handle,rv;

   rv=kc_ptr2id((char*)get_kto_check_version_x(mode),&handle,0);
   if(rv<0)
      return -1;
   else
      return handle;
}

DLL_EXPORT int current_lutfile_name_id(int *set,int *level,int *retval)
{
   int handle,rv;

   rv=kc_ptr2id((char*)current_lutfile_name(set,level,retval),&handle,0);
   if(rv<0)
      return -1;
   else
      return handle;
}


/* Funktionen kc_ptr2id(), kc_id2ptr() und kc_id_free() +§§§1 */
/* ###########################################################################
 * # Die folgenden Funktionen dienen dazu, ein Array von (char-)Pointern     #
 * # aufzubauen, in dem die Adressen von allokierten Strings gespeichert     #
 * # werden. Die Routinen, die Speicher für Strings allokieren, können dann  #
 * # in der DLL die String-Routinen direkt verwenden und müssen nicht mehr   #
 * # den etwas eigenwilligen (Schleich-)Weg über IntPtr nehmen, damit der    #
 * # Speicher wieder freigegeben werden kann...                              #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

/* Funktion kc_ptr2id() +§§§2 */
/* ###########################################################################
 * # Die Funktion kc_ptr2id() sucht für einen Pointer einen freien Slot      #
 * # in dem Array handle_ptr[]; falls kein Platz mehr in dem Array ist oder  #
 * # es noch nicht initialisiert wurde, wird es erweitert.                   #
 * #                                                                         #
 * # Falls die Variable release_mem 1 ist wird der Speicher bei Aufruf der   #
 * # Funktion kc_id_free() wieder freigegeben, andernfalls bleibt der Pointer#
 * # erhalten. Beim Aufruf mit release_mem=0 können somit auch String-       #
 * # Konstanten einem Handle zugeordnet werden. Falls die entsprechende      #
 * # Konstante schon ein Handle hat, wird dieses zurückgegeben; beim Aufruf  #
 * # von kc_id_free() wird es auch nicht gelöscht, der Funktionsaufruf gibt  #
 * # nur OK zurück, ohne etwas zu tun.                                       #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

#define HANDLE_CNT_INCREMENT 100

static int kc_ptr2id(char *ptr,int *handle,int release_mem)
{
   int i;

   *handle=-1; /* für evl. malloc-Fehler vorbelegen */
   if(!h_cnt){
      if(!(handle_ptr=(char **)calloc(sizeof(char*),HANDLE_CNT_INCREMENT)) || !(handle_free=(int*)calloc(sizeof(int),HANDLE_CNT_INCREMENT)))return ERROR_MALLOC;
      h_cnt=HANDLE_CNT_INCREMENT;
   }
   if(!release_mem)  /* Handle für fixen String, suchen ob er schon vergeben wurde */
      for(i=0;i<h_cnt;i++)if(handle_ptr[i]==ptr && !handle_free[i]){
         *handle=i;
         return OK;
      }
   for(i=0;i<h_cnt;i++)if(!handle_ptr[i]){
      *handle=i;
      handle_ptr[i]=ptr;
      handle_free[i]=release_mem;
      return OK;
   }
   if(!(handle_ptr=(char **)realloc(handle_ptr,sizeof(char*)*(h_cnt+HANDLE_CNT_INCREMENT)))
         || !(handle_free=(int*)realloc(handle_free,sizeof(int)*(h_cnt+HANDLE_CNT_INCREMENT))))return ERROR_MALLOC;
   h_cnt+=HANDLE_CNT_INCREMENT;
   *handle=i;
   handle_ptr[i]=ptr;
   handle_free[i++]=release_mem;
   for(;i<h_cnt;i++){
      handle_ptr[i]=NULL;
      handle_free[i]=0;
   }
   return OK;
}

/* Funktion kc_id2ptr() +§§§2 */
/* ###########################################################################
 * # Diese Funktion gibt den Pointer zu einem Handle zurück. Dieser Wert     #
 * # kann dann als String-Pointer in den DLL-Routinen verwendet werden.      #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT char *kc_id2ptr(int handle,int *retval)
{
   if(handle>=0 && handle<h_cnt && handle_ptr[handle]){
      if(retval)*retval=OK;
      return handle_ptr[handle];
   }
   else{
      if(retval)*retval=INVALID_HANDLE;
      return "";
   }
}

/* Funktion kc_id_free() +§§§2 */
/* ###########################################################################
 * # Diese Funktion gibt den Speicher, der zu einem Handle gehört, wieder    #
 * # frei und setzt den entsprechenden Slot-Eintrag auf NULL.                #
 * #                                                                         #
 * # Copyright (C) 2014 Michael Plugge <m.plugge@hs-mannheim.de>             #
 * ###########################################################################
 */

DLL_EXPORT int kc_id_free(int handle)
{
   if(handle>=0 && handle<h_cnt && handle_ptr[handle]){
      if(handle_free[handle]){  /* Freigabe nur bei allokiertem Speicher */
         free(handle_ptr[handle]);
         handle_ptr[handle]=NULL;
         handle_free[handle]=0;
      }
      return OK;
   }
   return INVALID_HANDLE;
}


#else /* !INCLUDE_KONTO_CHECK_DE */
/* Leerdefinitionen für !INCLUDE_KONTO_CHECK_DE +§§§1 */
#include "konto_check.h"

#define EXCLUDED     {return EXCLUDED_AT_COMPILETIME;} 
#define EXCLUDED_V   {} 
#define EXCLUDED_VP  {return NULL;} 
#define EXCLUDED_S   {return "EXCLUDED_AT_COMPILETIME";}
#define XI DLL_EXPORT int
#define XV DLL_EXPORT void
#define XC DLL_EXPORT char *
#define XCC const DLL_EXPORT char *

XI kto_check_blz(char *blz,char *kto)EXCLUDED
XI kto_check_pz(char *pz,char *kto,char *blz)EXCLUDED
XI kto_check(char *pz_or_blz,char *kto,char *lut_name)EXCLUDED
XI kto_check_t(char *pz_or_blz,char *kto,char *lut_name,KTO_CHK_CTX *ctx)EXCLUDED
XCC kto_check_str(char *pz_or_blz,char *kto,char *lut_name)EXCLUDED_S
XI kto_check_regel(char *blz,char *kto)EXCLUDED
XI kto_check_regel_dbg(char *blz,char *kto,char *blz2,char *kto2,const char **bic,int *regel,RETVAL *retvals)EXCLUDED
XI cleanup_kto(void)EXCLUDED
XI cleanup_kto_t(KTO_CHK_CTX *ctx)EXCLUDED
XI generate_lut(char *inputname,char *outputname,char *user_info,int lut_version)EXCLUDED
XI get_lut_info(char **info,char *lut_name)EXCLUDED
XI get_lut_info_b(char **info,char *lutname)EXCLUDED;
XI get_lut_info2_b(char *lutname,int *version,char **prolog_p,char **info_p,char **user_info_p)EXCLUDED;
XI get_lut_info_t(char **info,char *lut_name,KTO_CHK_CTX *ctx)EXCLUDED
XI get_lut_info2(char *lut_name,int *version_p,char **prolog_p,char **info_p,char **user_info_p)EXCLUDED
XI get_lut_id(char *lut_name,int set,char *id)EXCLUDED
XCC get_kto_check_version(void)EXCLUDED_S
XCC get_kto_check_version_x(int mode)EXCLUDED_S;
XI create_lutfile(char *name, char *prolog, int slots)EXCLUDED
XI write_lut_block(char *lutname, UINT4 typ,UINT4 len,char *data)EXCLUDED
XI read_lut_block(char *lutname, UINT4 typ,UINT4 *blocklen,char **data)EXCLUDED
XI read_lut_slot(char *lutname, int slot,UINT4 *blocklen,char **data)EXCLUDED
XI lut_dir_dump(char *filename,char *outputname)EXCLUDED
XI lut_dir_dump_str(char *lutname,char **dptr)EXCLUDED
XI generate_lut2_p(char *inputname,char *outputname,char *user_info,char *gueltigkeit,
      UINT4 felder,UINT4 filialen,int slots,int lut_version,int set)EXCLUDED
XI generate_lut2(char *inputname,char *outputname,const char *user_info,char *gueltigkeit,
      UINT4 *felder,UINT4 slots,UINT4 lut_version,UINT4 set)EXCLUDED
XI copy_lutfile(char *old_name,char *new_name,int new_slots)EXCLUDED
XCC current_lutfile_name(int *set,int *level,int *retval)EXCLUDED_S;
XI lut_init(char *lut_name,int required,int set)EXCLUDED
XI kto_check_init(char *lut_name,int *required,int **status,int set,int incremental)EXCLUDED
XI kto_check_init_p(char *lut_name,int required,int set,int incremental)EXCLUDED
XI lut_info(char *lut_name,char **info1,char **info2,int *valid1,int *valid2)EXCLUDED
XI lut_info_b(char *lut_name,char **info1,char **info2,int *valid1,int *valid2)EXCLUDED
XI lut_info_id(char *lut_name,int *info1,int *info2,int *valid1,int *valid2)EXCLUDED
XI lut_valid(void)EXCLUDED
XI lut_multiple(char *b,int *cnt,int **p_blz,char  ***p_name,char ***p_name_kurz,int **p_plz,char ***p_ort,
      int **p_pan,char ***p_bic,int *p_pz,int **p_nr,char **p_aenderung,char **p_loeschung,int **p_nachfolge_blz,
      int *id,int *cnt_all,int **start_idx)EXCLUDED
XI lut_filialen(char *b,int *retval)EXCLUDED
XI dump_lutfile(char *outputname,UINT4 *required)EXCLUDED
XI dump_lutfile_p(char *outputname,UINT4 felder)EXCLUDED
XI lut_blz(char *b,int zweigstelle)EXCLUDED
XI lut_blz_i(int b,int zweigstelle);
XCC lut_name(char *b,int zweigstelle,int *retval)EXCLUDED_S
XCC lut_name_i(int b,int zweigstelle,int *retval)EXCLUDED_S
XCC lut_name_kurz(char *b,int zweigstelle,int *retval)EXCLUDED_S
XCC lut_name_kurz_i(int b,int zweigstelle,int *retval)EXCLUDED_S
XI lut_plz(char *b,int zweigstelle,int *retval)EXCLUDED
XI lut_plz_i(int b,int zweigstelle,int *retval)EXCLUDED
XCC lut_ort(char *b,int zweigstelle,int *retval)EXCLUDED_S
XCC lut_ort_i(int b,int zweigstelle,int *retval)EXCLUDED_S
XI lut_pan(char *b,int zweigstelle,int *retval)EXCLUDED
XI lut_pan_i(int b,int zweigstelle,int *retval)EXCLUDED
XCC lut_bic(char *b,int zweigstelle,int *retval)EXCLUDED_S
XCC lut_bic_i(int b,int zweigstelle,int *retval)EXCLUDED_S
XI lut_nr(char *b,int zweigstelle,int *retval)EXCLUDED
XI lut_nr_i(int b,int zweigstelle,int *retval)EXCLUDED
XI lut_pz(char *b,int zweigstelle,int *retval)EXCLUDED
XI lut_pz_i(int b,int zweigstelle,int *retval)EXCLUDED
XI lut_aenderung(char *b,int zweigstelle,int *retval)EXCLUDED
XI lut_aenderung_i(int b,int zweigstelle,int *retval)EXCLUDED
XI lut_loeschung(char *b,int zweigstelle,int *retval)EXCLUDED
XI lut_loeschung_i(int b,int zweigstelle,int *retval)EXCLUDED
XI lut_nachfolge_blz(char *b,int zweigstelle,int *retval)EXCLUDED
XI lut_nachfolge_blz_i(int b,int zweigstelle,int *retval)EXCLUDED
XI lut_iban_regel(char *b,int zweigstelle,int *retval)EXCLUDED
XI lut_iban_regel_i(int b,int zweigstelle,int *retval)EXCLUDED
XI lut_cleanup(void)EXCLUDED
XI bic_aenderung(char *bic_name,int mode,int filiale,int*retval)EXCLUDED
XI biq_aenderung(int idx,int*retval)EXCLUDED
XI iban_aenderung(char *iban,int filiale,int*retval)EXCLUDED
XI bic_loeschung(char *bic_name,int mode,int filiale,int*retval)EXCLUDED
XI biq_loeschung(int idx,int*retval)EXCLUDED
XI iban_loeschung(char *iban,int filiale,int*retval)EXCLUDED
XI bic_iban_regel(char *bic_name,int mode,int filiale,int*retval)EXCLUDED
XI biq_iban_regel(int idx,int*retval)EXCLUDED
XI iban_iban_regel(char *iban,int filiale,int*retval)EXCLUDED
XI bic_nachfolge_blz(char *bic_name,int mode,int filiale,int*retval)EXCLUDED
XI biq_nachfolge_blz(int idx,int*retval)EXCLUDED
XI iban_nachfolge_blz(char *iban,int filiale,int*retval)EXCLUDED
XI bic_nr(char *bic_name,int mode,int filiale,int*retval)EXCLUDED
XI biq_nr(int idx,int*retval)EXCLUDED
XI iban_nr(char *iban,int filiale,int*retval)EXCLUDED
XI bic_pan(char *bic_name,int mode,int filiale,int*retval)EXCLUDED
XI biq_pan(int idx,int*retval)EXCLUDED
XI iban_pan(char *iban,int filiale,int*retval)EXCLUDED
XI bic_plz(char *bic_name,int mode,int filiale,int*retval)EXCLUDED
XI biq_plz(int idx,int*retval)EXCLUDED
XI iban_plz(char *iban,int filiale,int*retval)EXCLUDED
XI bic_pz(char *bic_name,int mode,int filiale,int*retval)EXCLUDED
XI biq_pz(int idx,int*retval)EXCLUDED
XI iban_pz(char *iban,int filiale,int*retval)EXCLUDED
XCC bic_bic(char *bic_name,int mode,int filiale,int*retval)EXCLUDED_S
XCC biq_bic(int idx,int*retval)EXCLUDED_S
XCC iban_bic(char *iban,int filiale,int*retval)EXCLUDED_S
XCC bic_bic_h(char *bic_name,int mode,int filiale,int*retval)EXCLUDED_S
XCC biq_bic_h(int idx,int*retval)EXCLUDED_S
XCC iban_bic_h(char *iban,int filiale,int*retval)EXCLUDED_S
XCC bic_name(char *bic_name,int mode,int filiale,int*retval)EXCLUDED_S
XCC biq_name(int idx,int*retval)EXCLUDED_S
XCC iban_name(char *iban,int filiale,int*retval)EXCLUDED_S
XCC bic_name_kurz(char *bic_name,int mode,int filiale,int*retval)EXCLUDED_S
XCC biq_name_kurz(int idx,int*retval)EXCLUDED_S
XCC iban_name_kurz(char *iban,int filiale,int*retval)EXCLUDED_S
XCC bic_ort(char *bic_name,int mode,int filiale,int*retval)EXCLUDED_S
XCC biq_ort(int idx,int*retval)EXCLUDED_S
XCC iban_ort(char *iban,int filiale,int*retval)EXCLUDED_S
XI kto_check_encoding(int mode)EXCLUDED
XI keep_raw_data(int mode)EXCLUDED
XCC kto_check_encoding_str(int mode)EXCLUDED_S
XCC kto_check_retval2txt(int retval)EXCLUDED_S
XCC kto_check_retval2txt_short(int retval)EXCLUDED_S
XCC kto_check_retval2html(int retval)EXCLUDED_S
XCC kto_check_retval2dos(int retval)EXCLUDED_S
XCC kto_check_retval2utf8(int retval)EXCLUDED_S
XI rebuild_blzfile(char *inputname,char *outputname,UINT4 set)EXCLUDED
XI ci_check(char *ci)EXCLUDED
XI bic_check(char *search_bic,int *cnt)EXCLUDED
XI iban_check(char *iban,int *retval)EXCLUDED
XCC iban2bic(char *iban,int *retval,char *blz,char *kto)EXCLUDED_S
XCC iban2bic_id(char *iban,int *retval,int *blz,int *kto)EXCLUDED_S
XC iban_gen(char *kto,char *blz,int *retval)EXCLUDED_S
XI iban_gen_id(char *kto,char *blz,int *retval)EXCLUDED
XC char *iban_bic_gen(char *blz,char *kto,const char **bic,char *blz2,char *kto2,int *retval)EXCLUDED_S
XC char *iban_bic_gen1(char *blz,char *kto,const char **bic,int *retval)EXCLUDED_S
XI ipi_gen(char *zweck,char *dst,char *papier)EXCLUDED
XI ipi_gen_id(char *zweck,int *dst,int *papier)EXCLUDED
XI iban_bic_gen_id(char *blz,char *kto,int *bic2,int *blz2,int *kto2,int *retval)EXCLUDED
XI ipi_check(char *zweck)EXCLUDED
XI kto_check_blz_dbg(char *blz,char *kto,RETVAL *retvals)EXCLUDED
XI kto_check_pz_dbg(char *pz,char *kto,char *blz,RETVAL *retvals)EXCLUDED
XC kto_check_test_vars(char *txt,UINT4 i)EXCLUDED_S
XI set_verbose_debug(int mode)EXCLUDED
XCC pz2str(int pz,int *ret)EXCLUDED_S
XI lut_suche_bic(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)EXCLUDED
XI lut_suche_namen(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)EXCLUDED
XI lut_suche_namen_kurz(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)EXCLUDED
XI lut_suche_ort(char *such_name,int *anzahl,int **start_idx,int **zweigstellen_base,
      char ***base_name,int **blz_base)EXCLUDED
XI lut_suche_blz(int such1,int such2,int *anzahl,int **start_idx,int **zweigstellen_base,int **base_name,int **blz_base)EXCLUDED
XI lut_suche_pz(int such1,int such2,int *anzahl,int **start_idx,int **zweigstellen_base,int **base_name,int **blz_base)EXCLUDED
XI lut_suche_plz(int such1,int such2,int *anzahl,int **start_idx,int **zweigstellen_base,int **base_name,int **blz_base)EXCLUDED
XI lut_suche_regel(int such1,int such2,int *anzahl,int **start_idx,int **zweigstellen_base,int **base_name,int **blz_base)EXCLUDED
XI lut_suche_volltext(char *such_wort,int *anzahl,int *base_name_idx,char ***base_name,int *zweigstellen_anzahl,int **start_idx,int **zweigstellen_base,int **blz_base)EXCLUDED
XI lut_suche_init(int uniq)EXCLUDED
XI lut_suche_free(int id)EXCLUDED
XI lut_suche_set(int such_id,int idx,int typ,int i1,int i2,char *txt)EXCLUDED
XI lut_suche(int such_id,char *such_cmd,UINT4 *such_cnt,UINT4 **filiale,UINT4 **blz)EXCLUDED
XI lut_suche_multiple(char *such_str,int uniq,char *such_cmd,UINT4 *anzahl,UINT4 **zweigstellen,UINT4 **blz)EXCLUDED
XI lut_suche_sort1(int anzahl,int *blz_base,int *zweigstellen_base,int *idx,int *anzahl_o,int **idx_op,int **cnt_op,int uniq)EXCLUDED
XI lut_suche_sort2(int anzahl,int *blz,int *zweigstellen,int *anzahl_o,int **blz_op,int **zweigstellen_op,int **cnt_o,int uniq)EXCLUDED
XI lut_blocks(int mode,char **lut_filename,char **lut_blocks_ok,char **lut_blocks_fehler)EXCLUDED
XI lut_blocks_id(int mode,int *lut_filename,int *lut_blocks_ok,int *lut_blocks_fehler)EXCLUDED
XI kto_check_init_default(char *lut_name,int block_id)EXCLUDED
XI kto_check_default_keys(char ***keys,int *cnt)EXCLUDED
XI kto_check_set_default(char *key,char *val)EXCLUDED
XI kto_check_set_default_bin(char *key,char *val,int size)EXCLUDED
XI kto_check_get_default(char *key,char **val,int *size)EXCLUDED
XI kto_check_write_default(char *lutfile,int block_id)EXCLUDED
XV kc_free(char *ptr)EXCLUDED_V
DLL_EXPORT void *kc_alloc(int size,int *retval)EXCLUDED_VP
XI set_default_compression(int mode)EXCLUDED
XI lut_keine_iban_berechnung(char *iban_blacklist,char *lutfile,int set)EXCLUDED
XI pz_aenderungen_enable(int set)EXCLUDED
XC kc_id2ptr(int handle,int *retval)EXCLUDED_S
XI kc_id_free(int handle)EXCLUDED
#endif
