/*========================================================================*\
 |  Datei: jpc.c                                      Datum: 07 Jun 1998  |
 *------------------------------------------------------------------------*
 |                  Auswertung des Katalog-CDROMs von JPC                 |
 |                                                                        |
\*========================================================================*/

char version[] = "$VER:JPC_kat 1.63 (07.06.98)";

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <signal.h>
#include <exec/types.h>         /* typedef's für UBYTE etc. */
#include "jpc.h"


char win0[80];                  /* das Debug-Fenster */
FILE *dbugf = NULL;
char *dbpath[DBMAX];            /* Verzeichnisnamen, "JPCPOP" etc. */
char dbcode[DBMAX][20];         /* Namen der Init-Dateien, "DB_1" etc. */
char indpath[MAXINDEX + 1][20]; /* Verzeichnisname, z. B. "KOMPO" */
char indname[MAXINDEX + 1][20]; /* z. B. "Komponist" */
int indcode[MAXINDEX + 1];      /* interne Kennummern, z. B. 46 */
char indshort[MAXINDEX + 1];    /* Kennbuchstaben, z. B. 'K' */
int indexes;
char fnamebuf[MAXFNAMES][20];   /* z. B. "Interpret" */
char *fieldname[256];           /* verweist auf Einträge in fnamebuf[] */
UBYTE ibm_decode[256], sort[256];       /* Zeichentabellen */
UWORD thisdb;                   /* welche der drei Datenbanken? */
long int reccnt;                /* Größe der Datenbank */
char *selected = NULL;          /* ein Flag pro Datensatz */
long int selcnt;                /* Summe über selected[] */
int targets;
char target[MAXTARGET][80];     /* Suchwörter */
int blksize;                    /* i. a. 2048 */
int recnumsize;                 /* 2 oder 3 Bytes */
int linelen;                    /* Format der Kurztext-Dateien */
char separator;                 /* normalerweise '|' */
int envconfig = 0;              /* über s: oder env: konfiguriert? */


void cli_help( char *myname )
/* Erklärung der CLI-Parameter */
    {
    printf( "Benutzung: \e[2m%s [-d]\e[0m\n", myname );
    printf( " -d: Debug-Ausgaben einschalten\n" );
    }


long getvalue( FILE *datei, char *keywd )
/* aus der Datei Zeilen lesen, bis eine <keywd> enthält, numerischen */
/* Wert vom Zeilenende zurückgeben, -1, wenn keine Zahl zu finden ist. */
    {
    int i, l;
    char s[80];

    l = strlen (keywd);
    do  {
        fgets (s, 80, datei);
        }
    while( strstr( s, keywd ) == NULL );
    i = strlen( s );
    while( !isdigit( s[--i] ) )
        if( i < l )
            return -1;
    while( isdigit ( s[--i] ) )
        ;
    TRACE2( "%s=%ld\n", keywd, atol (s + i + 1) );
    return atol( s + i + 1 );
    }


void setup()
/* globale Variablen initialisieren */
    {
    int c, i, j, m, n;
    UBYTE *s, sbuf[80];
    FILE *datei;
    char tab[] = "ÇüéâäàáçêëèïîìÄÅÉæÆôöòûùÿÖÜø£Ø×fáíóúñÑªº¿®¬½¼¡«»";
    static char leer = '\0';

    /* Decodierung des IBM-Zeichensatzes: */
    for (c = 0; c < 128; c++)
        ibm_decode[c] = c;
    for (c = 128; c < 176; c++)
        ibm_decode[c] = tab[c - 128];
    for (c = 176; c < 256; c++)
        ibm_decode[c] = ' ';        /* %-) */
    ibm_decode[ 13 ] = ' ';
    ibm_decode[ 225 ] = 'ß';
    /* Einen Katalog auswählen: */
    if (!(datei = fopen ("JPC:jpc/eps.ini", "r")))
      exit (20);
    getvalue (datei, "[DATABASE]");
    m = getvalue (datei, "DB_COUNT");
    printf ("\n");
    for( i = 0; i < m; i++ )
        {
        fscanf (datei, "%s", dbcode[i]);
        s = strchr (dbcode[i], '=');
        *s = '\0';
        dbpath[i] = s + 1;
        printf ("Kat. %d: %s\n", i, dbpath[i]);
        }
    fclose( datei );              /* "eps.ini" */
    printf( "Katalog? " );
    gets( sbuf );
    thisdb = atoi( sbuf );
    thisdb %= m;
    /* Datenfeldnamen ermitteln: */
    for (i = 0; i < 256; i++)
      fieldname[i] = &leer;
    sprintf (sbuf, "JPC:jpc/%s.ini", dbcode[thisdb]);
    datei = fopen (sbuf, "r");
    getvalue (datei, "[SLIST]");
    do
      fgets( sbuf, 80, datei );
    while( strncmp (sbuf, "SEPARATOR", 9) != 0);
    separator = ibm_decode[ sbuf[10] ];
    linelen = getvalue (datei, "LINELEN");
    getvalue (datei, "[KATEGORIES]");
    m = getvalue (datei, "MAXKAT");
    n = 0;
    do
      {
        fgets (sbuf, 80, datei);
        if (strncmp (sbuf, "KAT", 3) == 0)
          {
            i = atoi (sbuf + 3);
            if ((s = strchr (sbuf, '@')))
              {
                strcpy (fnamebuf[n], s + 1);
                if ((s = strchr (fnamebuf[n], ',')))
                  *s = '\0';
                fieldname[i] = fnamebuf[n];
                n++;
                TRACE2( "%3d %s\n", i, fieldname[i] );
              }
          }
      }
    while (i < m);
    fieldname[39] = "Neuheit:";
    fieldname[41] = "Trägermedium:";
    if (!*fieldname[43])
      fieldname[43] = "Kategorie:";
    if (!*fieldname[82])
      fieldname[82] = "Bewertung:";
    fclose (datei);               /* "db_x.ini" */
    /* Indexnamen (entsprechen überwiegend den Datenfeldnamen): */
    sprintf (sbuf, "JPC:%s/%s.glb", dbpath[thisdb], dbpath[thisdb]);
    datei = fopen (sbuf, "r");
    reccnt = getvalue (datei, "RECCOUNT");
    recnumsize = getvalue (datei, "ART_NO_LEN");
    blksize = getvalue (datei, "HIT_BLOCK_LEN");
    indexes = getvalue (datei, "KEY_COUNT");
    n = 0;
    for (j = 0; j < indexes; j++)
      {
        do
          fscanf (datei, "%s", sbuf);
        while( strcmp (sbuf, "KEY:") != 0 )
          ;
        fscanf( datei, "%s", indpath[MAXINDEX] );
        TRACE1( "%s\r\e[10C", indpath[MAXINDEX] );
        indcode[MAXINDEX] = getvalue (datei, "KAT");
        switch( indcode[MAXINDEX] )
          {
          case 70:
            strcpy (indname[MAXINDEX], "Volltext");
            break;
          default:
            strcpy (indname[MAXINDEX], fieldname[indcode[MAXINDEX]]);
          }
        if( (s = strchr( indname[MAXINDEX], ':' )) )
          *s = '\0';              /* ggf. Doppelpunkt killen */
        TRACE1( "\e[A\e[20C%s\n", indname[MAXINDEX] );
        /* Falls mehrere Indexe sich auf dasselbe Datenfeld beziehen, soll */
        /* sich nur der durchsetzen, der keine Wortfolgen enthält: */
        for (i = 0; i < n; i++)
          if (indcode[i] == indcode[MAXINDEX])
            break;
        if (i < n)
          {                       /* Nummer bereits vergeben. Wer hat recht? */
            do
              {
                fgets (sbuf, 80, datei);
              }
            while (strstr (sbuf, "PHRASE") == NULL);
            if (strchr (sbuf, 'Y'))
              i = n;              /* der alte darf bleiben */
          }
        else
          i = n++;                /* neues Feld anlegen */
        if (i < n)
          {
            strcpy (indpath[i], indpath[MAXINDEX]);
            strcpy (indname[i], indname[MAXINDEX]);
            indcode[i] = indcode[MAXINDEX];
          }
      }
    indexes = n;
    fclose (datei);
    fieldname[60] = &leer;
    fieldname[70] = &leer;        /* Tracks und Presse */
    strcpy( indshort, "KWTBLPMAVUR" );
    /* Sortiertabelle: */
    sprintf (sbuf, "JPC:%s/norm.stb", dbpath[thisdb]);
    datei = fopen (sbuf, "r");
    fread (sort, sizeof (char), 256, datei);
    fclose (datei);               /* jpcpop.glb */

    /* Speicher für die Bitmap reservieren: */
    if( selected != NULL )
        free( selected );
    selected = (char *)calloc( reccnt, sizeof( char ) );
    selcnt = 0;
    if( selected == NULL )
        {
        printf ("Fehler: kein Speicher für Bitmap (%ld Byte)\n", reccnt);
        exit (20);
        }
    }


void info()
    {
    printf( "\f \n\e[7m%35s%-35s\e[0m\n", "Recherche-Programm zum JPC Mu",
          "sik-/Video-Katalog auf CD-ROM" );
    printf( "%32s%-38s\n", "Version ", version + 13 );
    printf( "%35s%-35s\n\n", "© 1994-1998 Wilhelm Nöker <wn",
          "oeker@t-online.de>   FREEWARE" );
    printf( "%35s%-35s\n", "CD-ROM: DM 39.95 bei JPC, Lübecke",
          "r Str. 9, 49124 Georgsmarienhütte" );
    printf( "%35s%-35s\n", "Tel. 0180/525 1717, T-Online: *J",
          "PC#, Internet: http://www.jpc.de" );
    }


void help()
    {
    int i;

    printf( "\nDatenbank: %s (%ld Datensätze). Indexnamen:",
          dbpath[thisdb], reccnt );
    for( i = 0; i < indexes; i++ )
        {
        if( (i % 5) == 0 )
        printf( "\n" );
        printf( "\r\e[%dC", 15 * (i % 5) + 1 );
        printf( "\e[2m%c\e[0m=%s", indshort[i], indname[i] );
        }
    printf( "\n%s%s\n", "Kommandos: Zeigen, s/Speichern, q/Quit, Neustart, ",
          "oder Suchanfrage, z. B.:" );
    switch( thisdb )
        {
        case 0:
            printf(" t=berg?aga* |t=schneewa* &~v=heino &p<20 &l=88-99\n");
            break;
        case 1:
            printf(" l=?dd |l=9? &w=zauberfl* &~p<30\n");
            break;
        case 2:
            printf(" t=j |t=james &t=stewar? &l=1940-1950 &p<30\n");
            break;
        }
    printf( "weitere Einschränkung möglich durch: f/Finde <Wortfolge>\n" );
    printf( "\e[2m%s\e[0m",
          "\e[3A\e[11CZ\e[7Cs\e[CS\e[10Cq\e[CQ\e[5CN\n\n\e[37Cf\e[CF\n" );
    }


void by_key()
    {
    int ende = FALSE, saveme = FALSE;
    int i, j, k, m, ind, mode, op;
    UBYTE eing[200];
    UBYTE key0[80], key1[80];

    targets = 0;
    help();
    while( !ende )
        {
        printf( "\n%ld.Kommando: ", selcnt );
        if( fgets( eing, 200, stdin ) == NULL )
            {
            printf( "Hey!\n" );
            break;
            }
        m = strlen (eing);
        i = 0;
        while (isspace (eing[i]))
            i++;
        if( i == m )
            help ();
        while( i < m && !ende )
            {
            /* Recherchekommando? */
            mode = 5;           /* Maske: 4=neue Auswahl? 2=negieren? 1=erw./_einschr.? */
            while (strchr ("&|~", eing[i]))
                {               /* log. Operatoren? */
                switch (eing[i])
                    {
                    case '&':
                        mode &= 2;
                        break;
                    case '|':
                        mode &= 2;
                        mode |= 1;
                        break;
                    case '~':
                        mode |= 2;
                        break;
                    }
                    i++;
                }
            ind = -1;
            op = ' ';
            for( k = 0; k < indexes; k++ )      /* Indexbezeichner */
                if( toupper (eing[i]) == indshort[k] )
                    ind = k;
            if( ind >= 0 )
                {               /* Vergleichsoperator folgt */
                i++;
                op = eing[i++];
                }
            if( strchr ("<=>", op) )
                {
                j = k = i;
                while( eing[j] > ' ' )
                    {
                    if (eing[j] == '-')
                        k = j + 1;
                    j++;
                    }
                eing[ j ] = '\0';
                strcpy( key1, eing + k );
                if( k > i )
                    {           /* Bereichsangabe mit '-'? */
                    eing[ k - 1 ] = '\0';
                    strcpy( key0, eing + i );
                    }
                else
                    strcpy( key0, key1 );
                i = j + 1;
                civilize( key0, indshort[ind] == 'P' );
                civilize( key1, indshort[ind] == 'P' );
                if( op == '>' )
                    strcpy( key1, "*" );
                if( op == '<' )
                    strcpy( key0, "*" );
                printf ("%s Auswahl: %s%s%s", (mode & 4) ? "neue" :
                    (( mode & 1 ) ? "erweiternde" : "einschränkende"),
                    indname[ind], (mode & 2) ? "<>" : "=", key0 );
                if( strcmp (key0, key1) != 0 )
                    printf( "-%s", key1 );
                printf( "\n" );
                if( mode & 4 )
                    clr_select();
                hunt( ind, key0, key1 );
                printf( "Auswertung ... " );
                fflush( stdout );
                eval_select( mode & 3 );
                printf( "%ld Datensätze\n", selcnt );
                if( mode & 4 )  /* neue Auswahl, gemerkte Stichwörter löschen */
                    targets = 0;
                /* Stichwörter, die sich auf die großen Textblöcke beziehen, merken: */
                if( strchr ("TV", indshort[ind]) && strcmp (key0, key1) == 0
                    && (mode & 2) == 0 && targets < MAXTARGET)
                    strcpy (target[targets++], key0);
                }
            else
                {               /* kein Recherchekommando gefunden */
                switch (eing[i])
                    {
                    case 'z': case 'Z':
                        if (selcnt > 0)
                            browse();
                        break;
                    case 'q': case 'x':
                        saveme = TRUE;
                        /* drop-through! */
                    case 'Q': case 'X':
                        ende = TRUE;
                        break;
                    case 's':
                        saveall( FALSE );
                        break;
                    case 'S':
                        saveall( TRUE );
                        break;
                    case 'n': case 'N':
                        info();
                        setup();
                        help();
                        selcnt = 0;
                        targets = 0;
                        break;
                    case 'f': case 'F':
                        targets = 0;
                        k = i + 1;
                        do  {
                            j = k;
                            while( eing[ j ] && isspace( eing[ j ] ) )
                                j++;
                            k = j;
                            while( eing[ k ] && isgraph( eing[ k ] ) )
                                k++;
                            if (k > j)
                                {
                                strncpy( target[ targets ], eing + j, k - j );
                                target[ targets ][ k - j ] = '\0';
                                civilize( target[ targets ], FALSE);
                                targets++;
                                }
                            }
                        while( k > j && targets < MAXTARGET );
                        hand_auslese( eing[i] == 'F' );
                        break;
                    default:
                        help ();
                    }
                i = m;          /* "sonstiger Befehl" beendet die Eingabezeile */
                }
            while (isspace (eing[i]))
                i++;            /* zum nächsten Wort */
            }                   /* Ende einer Befehlszeile */
        }
    if( saveme )
        printf( "Fensterabmessungen in '%s' gesichert\n", writeconfig() );
    }


char* write_config( char* s )
    {
    FILE* config;

    config = fopen( s, "w" );
    fprintf( config, "%s\n%s\n%s\n%s\n%s\n%s\n", out1, out2, win0, win1, win2, win3 );
    fclose( config );
    return s;
    }


char* writeconfig()
/* Fensterpositionen sichern, Rückgabewert: Name der Konfigdatei */
    {
    if( envconfig )
        {
        write_config( "ENV:jpc.cfg" );
        return write_config( "ENVARC:jpc.cfg" );
        }
    else
        return write_config( "S:jpc.cfg" );
    }


int main( int argc, char *argv[] )
    {
    char sbuf[80], *s;
    int i, j, debugme = 0;
    FILE *config;

    /* Befehlszeile abarbeiten: */
    for (i = 1; i < argc; i++)
        {
        s = argv[i];
        if (*s == '-')
            switch (*++s)
                {
                case 'd':
                    debugme = 1;
                    break;
                default:
                    cli_help (argv[0]);
                    exit (5);
                }
        else
            {
            cli_help (argv[0]);
            exit (5);
            }
        }
    /* voreingestellte Dateinamen für Fenster und Ergebnisdateien: */
    strcpy (out1, "RAM:JPC-Kurzinfo");
    strcpy (out2, "RAM:JPC-Volltext");
    strcpy (win0, "CON:200/20/440/70/JPC-Debug-Info/INACTIVE");
    strcpy (win1, "RAW:0/11/580/245/aktuelle Auswahl");
    strcpy (win2, "RAW:200/0/430/256/Volltext");
    strcpy (win3, "RAW:50/100/540/80/JPC-Statusmeldung");
    config = fopen( "ENV:jpc.cfg", "r" );
    if( config != NULL )
        envconfig = 1;
    else
        config = fopen( "S:jpc.cfg", "r" );
    if( config )
        {
        for( i = 0; i < 6; i++ )
            {
            fgets( sbuf, 80, config );
            for( j = strlen( sbuf ) - 1; isspace( sbuf[j] ); j-- )
                sbuf[j] = '\0';
            switch( i )
                {
                case 0:
                    strcpy (out1, sbuf);
                    break;
                case 1:
                    strcpy (out2, sbuf);
                    break;
                case 2:
                    strcpy (win0, sbuf);
                    break;
                case 3:
                    strcpy (win1, sbuf);
                    break;
                case 4:
                    strcpy (win2, sbuf);
                    break;
                case 5:
                    strcpy (win3, sbuf);
                    break;
                }
            }
            fclose( config );
        }
    if( debugme )
        dbugf = fopen( win0, "r+" );
    info();
    setup();
    by_key();
    printf( "Und tschüß ...\n" );
    if( dbugf )
        fclose( dbugf );
    return 0;
    }

