/*************************************************************************\
  jpc.c: Auswertung des Katalog-CDROMs von JPC
  Kommandozeilen-Parameter:
    -d:         Debug-Ausgaben einschalten
\*************************************************************************/
  
char version[] = "$VER:JPC_kat 1.5 (13.03.97)";

#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"


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 */
int 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 */


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]))
    ;
  if (dbugf) fprintf(dbugf, "%s=%ld\n", keywd, atol(s+i+1));
  return atol(s+i+1);
}


void setup(void)
/* globale Variablen initialisieren */
{
  int c, i, j, m, n;
  char *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);
  if (thisdb<0) thisdb = 0;
  if (thisdb>=m) thisdb = m-1; 
  /* 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]");
  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++;
        if (dbugf) fprintf(dbugf, "%3d %s\n", i, fieldname[i]);
      }
    }
  } while (i<m);
  fieldname[39] = "Neuheit:";
  fieldname[41] = "Trägermedium:";
  if (!*fieldname[43]) fieldname[43] = "Kategorie:";
  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]);
    if (dbugf) fprintf(dbugf,"%s\r\e[10C", indpath[MAXINDEX]);
    indcode[MAXINDEX] = getvalue(datei, "KAT");
    if (indcode[MAXINDEX] == 70)
      strcpy(indname[MAXINDEX], "Volltext");
    else {    
      strcpy(indname[MAXINDEX], fieldname[indcode[MAXINDEX]]);
      if ((s = strchr(indname[MAXINDEX], ':')))
        *s = '\0'; /* Doppelpunkt killen */
    }
    if (dbugf) fprintf(dbugf, "\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, "KWTBLPMAVU");
  /* 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(void)
{
  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-1997 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(void)
{
  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, 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");
  }
  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[5CN\n\n\e[37Cf\e[CF\n");
}


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

  targets = 0;
  help();
  while (!ende) {
    printf("\n%ld.Kommando: ", selcnt); 
    gets(eing); 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 (isgraph(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, "*");
        if (mode>3) 
          printf("neue");
        else if (mode & 1) 
          printf("erweiternde");
        else
          printf("einschränkende");
        printf(" Auswahl: %s%s%s", 
            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 'Q': case 'x': 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 */
  }
}


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


int main(int argc, char *argv[])
{
  char sbuf[80], *s, win0[80];          /* das Debug-Fenster */
  int i, j, debugme=0, showcfg=0;
  FILE *config;

  /* Befehlszeile abarbeiten: */
  for (i=1; i<argc; i++) {
    s = argv[i];
    if (*s == '-')
      switch(*++s) {
        case 'd': debugme = 1; break;
        case 'c': showcfg = 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");
  if (showcfg) {
    printf("%s\n%s\n%s\n%s\n%s\n%s\n", out1, out2, win0, win1, win2, win3);
    exit(0);
  }        
  config = fopen("S:jpc.cfg", "r");
  if (!config)
    config = fopen("ENV: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;
}

