/* db2tex.c - data base to TeX;         UKE/EDV, Bernd Paradies, 18.10.90
 * Kleinere Änderungen: H. Astheimer, UKE-Kinderklinik, 16.4.91
 * Größere  Änderungen: K. Rath,      UKE-Kinderklinik, 20.1.92
 *
 *
 *                  Copyright (c) 1990, 1991, 1992
 *                Universitäts Krankenhaus Eppendorf
 *                 Abt. f. Hämatologie und Onkologie
 *                          Kinderklinik
 *                        Martinistraße 52
 *                        2000 Hamburg 20
 *
 *
 * AUTHOR:  Bernd Paradies
 *
 * SYNTAX:  dbtex [-hq][-n rep-lines] [-o output-file] [TeX-file] [rep-file]
 *
 * DESCRIPTION:
 *   dbtex setzt für Spaltennamen in TeX-Dateien den entsprechenden
 *   Spalteninhalt ein. Die Spalteninhalte werden über eine Datei im
 *   'Standard'-Report-Format eingelesen, wobei für jede Zeile der
 *   Report-Datei eine TeX-Datei mit den Spaltendaten erzeugt wird.
 *   Eine typische Anwendung für dbtex wäre z.B. ein Serienbrief, bei
 *   dem der Adressenkopf variiert.
 *
 * OPTIONS:
 *
 *  -n : setzt die maximale Anzahl der Zeilen, die von der Report-Datei
 *       eingelesen wird.
 *  -o : setzt einen neuen Namen für die Ausgabe-Dateien.
 *       dbtex -o brief.deu erzwingt Ausgabe in brief.deu
 *       (statt dbtex.def) und brief.deu2 (statt dbtex.inp).
 *  -q : unterdrückt die Ausgabe.
 *  -c : nur Compilieren
 *  -h : Hilfstext und Copyright
 *
 *
 * INTERNAS:
 *   Es wird zunächst ein Text-Rumpf erstellt und im zweiten
 *   Durchgang die Report-Datei Zeile für Zeile ausgewertet (GetReport).
 *   Dabei werden die Spalteninhalte dem Rumpf als Macros zugewiesen.
 *
 * FILES:
 *   db2tex.h:  header-file
 *   db2tex.c:  main
 *   db_tex.c:  Routinen für die Behandlung von TeX-Dateien
 *
 * BUGS:
 *   - beim Löschen der temporären Dateien wird keine weitere
 *     Überprüfung vorgenommen, ob z.B. das Original gelöscht wird.
 *   - die Fehlermeldungen und Warnungen sind in deutsch und englisch.
 *   27.12.90:
 *   - "dbtex a.tex a.rep" stellt nicht a.rep her.
 *   -
 *
 */

static char  sccsid[] = "@(#)db2tex ; v1.30/bp+kr ; 01/92";

#include "db2tex.h"


char    SpTab[MAXSPALTEN][50];
int     SpLen[MAXSPALTEN];
int     SpNr = 0;

int     TxtZeilen, GetRepZeilen, RepZeilen, DefZeilen, InpZeilen;
int     MaxReport = MAXREP;

BOOL    BeginDocument = FALSE;
BOOL    EndDocument   = FALSE;
FILE   *InpFile = NULL;
FILE   *DefFile = NULL;
FILE   *ShFile  = NULL;
FILE   *stdlog  = stderr;

int     OptQuiet   = FALSE;
int     OptCompile = FALSE;
int     OptOutput  = FALSE;
char   *prgname    = NULL;
char   *prgpath    = NULL;

#define   DelFile(nm)   if (!OptQuiet) printf("Lösche: %s\n",nm); unlink(nm);

/* ====================================================================== */

PUBLIC  FILE *_fopen(name, mode)
	char *name;
	char *mode;
{
FILE   *Txt;
char    Err[80];

  if ( (Txt = fopen (name, mode)) == NULL )
  {
    strcpy (Err, "Can't open file: ");
    strcat (Err, name);
    error (Err);
  }
  return (Txt);
}

/* ---------------------------------------------------------------------- */

PUBLIC  char *strtoupper(Str)
	char *Str;
{
REG ii;

  for (ii=0; ii != strlen (Str); ii++)
    Str[ii] = toupper (Str[ii]);
  return (Str);
}

/* ---------------------------------------------------------------------- */

PUBLIC char *delblank(Str)
       char *Str;
{
char *Text;

  Text = Str;
  while (*Text == BLANK)            /* die vorderen Leerzeichen entfernen */
    Text++;
  strcpy (Str, Text);
  Text = Str + strlen(Str) - 1;

  while ( (*Text == BLANK) && (Text != Str) )
  {
    *Text = 0;                      /* die hinteren entfernen */
     Text--;
  }
  return (Str);
}

/* ---------------------------------------------------------------------- */

PUBLIC char *ChkName(Name)
       char *Name;
{
char  UpName[MAXZEILE];
REG   ii;

  strtoupper(strcpy (UpName, Name));   /* alles in Groß-Buchstaben */

  for (ii=0; ii != SpNr; ii++)
    if (strncmp (SpTab[ii], UpName, strlen (SpTab[ii])) == 0)
      return (SpTab[ii]);                             /* gefunden ! */

  return (NULL);                                      /* nicht gefunden */
}

/* ---------------------------------------------------------------------- */

PUBLIC int   GetSQL(Zeile)
       char *Zeile;
{
char  *Zptr;
char   SpNamen[MAXZEILE];

  if ( (Zeile[0] != '%') || (Zeile[1] != '$') )
    error ("Falsches db2tex-Format: fehlende Spaltenbeschreibung in Zeile(1)");

  Zeile[strlen(Zeile)-1] = 0;                                /* \n löschen */
  Zptr = strtok (strcpy (SpNamen, strtoupper (Zeile)), " ");

  while ( Zptr != NULL )
  {
    if (SpNr > MAXSPALTEN)
      error ("Zuviele Spalten !");

    if ( (Zptr = strtok (NULL, " ")) != NULL )
      strcpy (SpTab[SpNr++], Zptr);
  }

  if (SpNr == 0)
    error ("Keine Spalten zu verarbeiten !\n");

  return (0);
}

/* ---------------------------------------------------------------------- */

PUBLIC int   GetReport(Nr,Zeile)
       int   Nr;
       char *Zeile;
{
int     NameNr = 0;
char   *Sptr;
REG     ii;

  if (Nr >= (MaxReport))  return (0);

  switch (Nr)
  {
    case 1:  Sptr = strtok (Zeile, " ");
	     while ( (Sptr != NULL) && (NameNr++ < SpNr) )
	       Sptr = strtok (NULL, " ");

	     if (SpNr > NameNr)
	       warning ("Es fehlen Spalten in der Report-Datei. Anzahl",
			(SpNr-NameNr) );
	     break;

    case 2:  for (ii=0; ii != SpNr; ii++)
	       SpLen[ii] = (ii==0) ? strlen (strtok (Zeile, SEP))
				   : strlen (strtok (NULL,  SEP));
	     break;

    default: PutTexRep(Nr, Zeile);
	     GetRepZeilen++;
	     break;
  }
  return (0);
}

/* ---------------------------------------------------------------------- */

PUBLIC int    WalkFile(Fname,Action)
       char  *Fname;
       int  (*Action)();
{
FILE  *Txt;
char   Zeile[MAXZEILE];
int    Nr = 0;

  Txt = _fopen (Fname, "r");

  while ( fgets (Zeile, MAXZEILE, Txt) != NULL )
    Action (++Nr, Zeile);

  fclose (Txt);
  return (Nr);    /* liefere Anzahl der gelesenen Zeilen zurück */
}

/* ---------------------------------------------------------------------- */

#define KEY_ZAHL   16

char *KeyWords[KEY_ZAHL] =
      { /* File-Parameter:
	   0       1         2      3        4      5                       */
	   "TEXT", "REPORT", "DEF", "INPUT", "DVI", "OUTPUT",
	/* TeX-Parameter:
	   6         7         8          9          10        11           */
	   "DVITPS", "DVITTY", "PRINTER", "TEXPOOL", "VIRTEX", "UMLT2TEX",
	/* Sonstiges:
	   12       13              14     15                               */
	   "QUIET", "COMPILE_ONLY", "SEP", "OUTDEV"};

PUBLIC int GetIni(IniFile)
FILE *IniFile;
{
   int  DateiEnde     = NULL;
   int  ConfigCounter = NULL;
   char zbuf[80];
   char *tbuf;
   int  Zaehler;
   int  EndLine = 0;

   while ( !DateiEnde )
   {
       DateiEnde = feof(IniFile);
       if ( DateiEnde )
       {
	   continue;
       }

       zbuf[0] = '\0';

       fgets(zbuf,80,IniFile);
       zbuf[strlen(zbuf)-1] = '\0';                  /* Strip LF            */

       if ( (strlen(zbuf) < 2) || (zbuf[0] == '#') ) /*Kommentare,Leerzeilen*/
       {
	   continue;
       }

       tbuf = (char *)strtok(zbuf,"=");
       for ( Zaehler = 0 ; Zaehler < KEY_ZAHL ; Zaehler++ )
       {
	   if ( strcmp(tbuf,KeyWords[Zaehler]) == NULL )
	   {
	       ConfigCounter++;
	       tbuf = (char *)NULL;
	       tbuf = (char *)strtok(NULL," ");
	       switch ( Zaehler )
	       {
		   case  0:                                 /* TEXT         */
			    strcpy(TxtName,tbuf);
			    break;
		   case  1:                                 /* REPORT       */
			    strcpy(RepName,tbuf);
			    break;
		   case  2:                                 /* DEF          */
			    strcpy(DefName,tbuf);
			    break;
		   case  3:                                 /* INPUT        */
			    strcpy(InpName,tbuf);
			    break;
		   case  4:                                 /* DVI          */
			    strcpy(DviName,tbuf);
			    break;
		   case  5:                                 /* OUTPUT       */
			    OptOutput = TRUE;
			    strcpy(OutName,tbuf);
			    break;
		   case  6:                                 /* DVITPS       */
			    DVITPS[0] = '\0';
			    sprintf(DVITPS,"%s/%s",TEXPOOL,tbuf);
			    EndLine = 0;
			    while ( !EndLine )
			    {
				tbuf = (char *)NULL;
				if ( (tbuf = (char *)strtok(NULL," ")) == NULL )
				{
				    EndLine++;
				    continue;
				}
				strcat(DVITPS," ");
				strcat(DVITPS,tbuf);
			    } /* ENDE: while */
			    break;
		   case  7:                                 /* DVITTY       */
			    DVITTY[0] = '\0';
			    sprintf(DVITTY,"%s/%s",TEXPOOL,tbuf);
			    EndLine = 0;
			    while ( !EndLine )
			    {
				tbuf = (char *)NULL;
				if ( (tbuf = (char *)strtok(NULL," ")) == NULL )
				{
				    EndLine++;
				    continue;
				}
				strcat(DVITTY," ");
				strcat(DVITTY,tbuf);
			    } /* ENDE: while */
			    break;
		   case  8:                                 /* PRINTER      */
			    PRINTER[0] = '\0';
			    if ( tbuf[0] == '$' )
				strcpy(PRINTER,getenv(&tbuf[1]));
			    else
				strcpy(PRINTER,tbuf);
			    break;
		   case  9:                                 /* TEXPOOL      */
			    TEXPOOL[0] = '\0';
			    if ( tbuf[0] == '$' )
				strcpy(TEXPOOL,getenv(&tbuf[1]));
			    else
				strcpy(TEXPOOL,tbuf);
			    break;
		   case 10:                                 /* VIRTEX       */
			    VIRTEX[0] = '\0';
			    sprintf(VIRTEX,"%s/%s",TEXPOOL,tbuf);
			    EndLine = 0;
			    while ( !EndLine )
			    {
				tbuf = (char *)NULL;
				if ( (tbuf = (char *)strtok(NULL," ")) == NULL )
				{
				    EndLine++;
				    continue;
				}
				strcat(VIRTEX," ");
				strcat(VIRTEX,tbuf);
			    } /* ENDE: while */
			    break;
		   case 11:                                 /* UMLT2TEX     */
			    UMLT2TEX[0] = '\0';
			    sprintf(UMLT2TEX,"%s/%s",TEXPOOL,tbuf);
			    break;
		   case 12:                                 /* QUIET        */
			    if ( strcmp(tbuf,"yes") == NULL )
				OptQuiet = TRUE;
			    break;
		   case 13:                                 /* COMPILE_ONLY */
			    if ( strcmp(tbuf,"yes") == NULL )
				OptCompile = TRUE;
			    break;
		   case 14:                                 /* SEP          */
			    SEP[0] = '\0';
/*                          strcpy(SEP,tbuf);*/
			    if (tbuf[0] == '\'' || tbuf[0] == '\"')
			      SEP[0] = ' ';
			    else
			      SEP[0] = tbuf[0];
			      SEP[1] = '\0';
			    break;
		   case 15:                                 /* OUTDEV       */
			    OUTDEV[0] = '\0';
			    strcpy(OUTDEV,tbuf);
			    break;

		   default: break;               /* Alles andere ignorieren */

	       } /* ENDE: switch(Zaehler) */
	       break;
	   }  /* ENDE: if(strcmp()) */
       } /* ENDE: for(Zaehler) */

   } /* ENDE: while(DateiEnde) */

   return(ConfigCounter);

} /* ENDE: GetIni() */

/* ---------------------------------------------------------------------- */

PRIVATE info(void)
{
REG  ii;

  if (!OptQuiet)
  {
    printf ("\n%s:\n", prgname);
    printf ("\t EINGABE: %s (Textdatei,   Z:%i)\n",   TxtName, TxtZeilen);
    printf ("\t EINGABE: %s (Reportdatei, Z:%i von %i)\n\n",
			     RepName, GetRepZeilen, RepZeilen);

    if (!OptCompile)
      printf ("\t AUSGABE: %s\n", OptOutput ? OutName : "(interaktiv)");
    else
    {
      printf ("\t AUSGABE: %s (Zwischendatei, Z:%i)\n", InpName,InpZeilen);
      printf ("\t AUSGABE: %s (Zwischendatei, Z:%i)\n", DefName, DefZeilen);
    }
    printf ("\n\t Max. Report-Zeilen: %i\n", MaxReport-3);
    if (SpNr != 0)
    {
      printf ("\t Benutzte Spalten: ");
      for (ii=0; ii!=SpNr; ii++)
	printf ("%s ", SpTab[ii]);
      printf ("\n");
    }
    printf ("\n");
  }
}

/* ---------------------------------------------------------------------- */

PRIVATE usage(void)
{
  printf ("\n");
  printf ("(c) UKE-Kinderklinik, Abt.f. Hämatologie und Onkologie, ");
  printf ("AG EDV & Statistik\n\n");

  printf ("%s   Ver 1.30, 24.01.92\n","db2tex - data base to TeX.", prgname);
  printf ("Usage: %s [-hqc][-n report-lines] [-o output-file] ", prgname);
  printf ("[TeX-file] [report-file] \n");
  printf ("Options:\n");
  printf ("\t -c : compile only\n");
  printf ("\t -n : set max. report lines\n");
  printf ("\t -o : set output file name\n");
  printf ("\t -q : quiet running\n");
  printf ("\t -h : this help text\n\n");
  printf ("Default file name: %s\n", TxtName);
  printf ("\n");
}

/* ---------------------------------------------------------------------- */

PRIVATE void atexit(void)
{
/*
  if (MemBlocks != 0)
    warning ("missing free ! - MemBlocks: ", MemBlocks);
*/
}


/* ---------------------------------------------------------------------- */

PUBLIC int   main(argc,argv,envp)
       int   argc;
       char *argv[];
       char *envp[];
{
IMPORT  char *optarg;
IMPORT  int   optind;
IMPORT  int   opterr;
REG     int   Opt;
FILE   *IniFile;
char    IniFileName_1[60];
char    IniFileName_2[20];

  /* -- Initialsierung */

  prgname = (char *)basename(argv[0]);         /* Eigenen Namen feststellen */
  prgpath = (char *)dirname(argv[0]);          /* wo bin gestartet ?        */

  sprintf(IniFileName_1,"%s/%s.ini",prgpath,prgname);
  sprintf(IniFileName_2,"%s.ini",prgname);

  TxtZeilen = GetRepZeilen = RepZeilen = DefZeilen = InpZeilen = 0;

  /* -- Diverse Variable vorbelegen, danach die Standard-Startdatei suchen, */
  /* -- anschließend evtl. eine individuelle Startdatei. Die Variablen wer- */
  /* -- in dieser Reihenfolge belegt und ggfls. überschrieben!              */
  /* -- Eingestellte Optionen werden von Kommandozeilen-Parametern evtl.    */
  /* -- nocheinmal überschrieben !!!                                        */

  /* Default-Belegung :
  */
  sprintf (TxtName, "%s.%s",  prgname, STDTEXNAME);
  sprintf (RepName, "%s.%s",  prgname, STDREPNAME);
  sprintf (DefName, "%s.%s",  prgname, STDDEFNAME);
  sprintf (InpName, "%s.%s",  prgname, STDINPNAME);
  sprintf (DviName, "%s.dvi", prgname);
  strcpy  (OutName, "");
  strcpy  (TEXPOOL, STDTEXPOOL);
  sprintf (VIRTEX,  "%s/%s",  TEXPOOL, STDVIRTEX);
  sprintf (DVITPS,  "%s/%s",  TEXPOOL, STDDVITPS);
  sprintf (DVITTY,  "%s/%s",  TEXPOOL, STDDVITTY);
  sprintf (PRINTER, "%s",     STDPRINTER);

  /* Nach .ini-Datei erst im Start- und dann im aktuellen Verzeichnis
  ** suchen :
  */
  if ( IniFile = fopen(IniFileName_1,"r") )
  {
      GetIni(IniFile);
      fclose(IniFile);
  }
  else
  {
      fprintf(stderr,"\n%s: Standard-Startdatei %s nicht gefunden!\n");
  } /* ENDE: if(IniFileName_1) */

  if ( IniFile = fopen(IniFileName_2,"r") )
  {
      GetIni(IniFile);
      fclose(IniFile);
  } /* ENDE: if(IniFileName_2) */

  /* -- Parameter-Auswertung */

  while ( (Opt = getopt (argc, argv, "hcqo:n:")) != EOF)
    switch (Opt)
    {
      case 'h' :  usage(); exit (0);                               break;
      case 'q' :  OptQuiet   = TRUE;                               break;/*i*/
      case 'n' :  MaxReport  = atoi (optarg);                      break;
      case 'c' :  OptCompile = TRUE;                               break;/*i*/
      case 'o' :  OptOutput  = TRUE; strcpy(OutName, optarg);      break;/*i*/
      default  :  usage();           error ("Unbekannte option");  break;
    }

  if (argv[optind] != NULL)
  {
    strcpy (TxtName, argv[optind]);
    if (argv[optind+1] != NULL)
      strcpy (RepName, argv[optind+1]);
  }


  /* -- Informationen */
  MaxReport += 3;
  info();

  /* -- GetTex und GetReport */

  do_tex();


  /* -- Abschluß-Statistik */

  DefZeilen += 5;
  info();

  if (!OptCompile)
  {
    if (!OptQuiet)
      printf ("Zwischendateien werden wieder gelöscht !\n");
      DelFile(DefName);
      DelFile(InpName);
      DelFile(DviName);
  }

  atexit();
  return (0);
}

/* -- end of file ------------------------------------------------------- */
