/*-------------------------------------------------------------------------*/
/*                                                                         */
/* HPTOMF : Konvertierung einer HPGL-Datei in eine METAFONT-Datei          */
/* (c) D. Donath 1990                                                      */
/*                                                                         */
/* Das Programm HPTOMF ist "public domain". Der Autor erteilt hiermit      */
/* die Erlaubnis, es zusammen mit dem Quelltext HPTOMF.C und der           */
/* Dokumentation HPTOMF.DOC weiterzugeben, zu veraendern und auf andere    */
/* Rechner zu uebertragen.                                                 */
/* Jegliche Garantieansprueche an den Autor sind ausgeschlossen.           */
/*                                                                         */
/*  Autor: Dirk Donath                                                     */
/*         Mitterhoferstr. 8                                               */
/*         7000 Stuttgart 40                                               */
/*                                                                         */
/*-------------------------------------------------------------------------*/

#include <stdio.h>

#define TRUE  1
#define FALSE 0

void   lese_befehl (void);
int    papr        (int absolut);
int    pupd        (int down);
int    ziffer      (char c);
void   schreiben   (int x1,int y1,int x2,int y2);
int    lesen       (int *x1ptr,int *y1ptr,int *x2ptr,int *y2ptr);
void   ausgabe     (void);

const  char str_ende  = 0;

int    stift_unten = TRUE;
int    xalt        = 0;
int    yalt        = 0;
int    xmin        = 30000;
int    xmax        = 0;
int    ymin        = 30000;
int    ymax        = 0;
int    zaehler     = 0;
int    laenge      = 0;

float  ysoll;
char   hpdatei [30];
char   mfdatei [30];
char   *const tddatei = "HPTOMF.TMP";
char   befehl [255];
FILE   *hd, *td, *md;


/*-------------------------------------------------------------------------*/
/*                        Beginn des Hauptprogramms                        */
/*-------------------------------------------------------------------------*/

int main (int argc, char *argv[])
{
  char c;
  int  i;

  printf("\nHPTOMF (c) Dirk Donath 1990\n\n");
  
  /* Auswertung der Kommandozeile: */
  if (argc != 4)
  {
    printf("Aufruf: HPTOMF [HPGL-Datei] [METAFONT-Datei] [Zeichnungshoehe in mm]\n");
    return(1);
  }
  sscanf(argv[1],"%s",&hpdatei);   /* Param. 1 = HPGL-Datei */
  sscanf(argv[2],"%s",&mfdatei);   /* Param. 2 = METAFONT-Datei */
  if (!sscanf(argv[3],"%d",&i))    /* Param. 3 = Zeichnungshoehe */
  {
    printf("- Zeichnungshoehe ungueltig\n");
    return(1);
  }
  ysoll = (float)i;

  /* Oeffnen der HPGL-Datei: */
  hd = fopen(hpdatei,"r");
  if (hd == NULL)
  {
    printf("- Fehler beim Oeffnen der HPGL-Datei \"%s\"\n",hpdatei);
    return(1);
  }

  /* Oeffnen der Temporaerdatei: */
  td = fopen(tddatei,"wb");
  if (td == NULL)
  {
    printf("- Fehler beim Erzeugen der Temporaerdatei \"%s\"\n",tddatei);
    return(1);
  }

  printf("- Lese HPGL-Datei \"%s\"\n",hpdatei);

  /* Befehl bis zum ';' lesen, dann das ';' ueberlesen: */
  while (fscanf(hd, "%[^;] %c",&befehl,c) > 0)
    lese_befehl();

  fclose(hd);
  fclose(td);
  
  ausgabe();
  
  return(0);
}


/*-------------------------------------------------------------------------*/
/*                      Einen HPGL-Befehl verarbeiten                      */
/*-------------------------------------------------------------------------*/

void lese_befehl ()

{
  int i = 0;
  int j;

  /* Unerlaubte Zeichen im String beseitigen: */
  while (befehl[i] != str_ende)
  {
    if (befehl[i] <= ' ')
    {
      j = i;
      while (befehl[j] != str_ende)
      {
        befehl[j] = befehl[j+1];
        j++;
      }
    }
    i++;
  }

  laenge= i; /* Stringlaenge merken */

  /* Befehl analysieren: */
  switch (befehl[0])
  {
    case 'P': switch (befehl[1])
              {
                case 'A': if (!papr(TRUE))  return; break;
                case 'R': if (!papr(FALSE)) return; break;
                case 'D': if (!pupd(TRUE))  return; break;
                case 'U': if (!pupd(FALSE)) return; break;
                default : return;
              }
    default : return;
  }
}


/*-------------------------------------------------------------------------*/
/*                 Pruefung, ob ein Zeichen eine Ziffer ist                */
/*-------------------------------------------------------------------------*/

int ziffer (char c)
{
  if ((c == '-') || ((c >= '0') && (c <= '9')))
    return(TRUE);
  else
    return(FALSE);
}


/*-------------------------------------------------------------------------*/
/*                     PA- oder PR-Befehl verarbeiten                      */
/*-------------------------------------------------------------------------*/

int papr (int absolut)

/* Der PA- oder PR-Befehl kann aus beliebig vielen x-y-Zahlenpaaren
   und/oder PU- oder PD-Befehlen bestehen.
   Die Zahlen sind jeweils durch Komma getrennt.
   Beispiel: PA PD0,0,80,50,90,20PU140,30PD150,80;    */
{
  int i,j,x,y,zahl,x_erwartet;
  char k[80];

  /* restlichen String auswerten: */
  x_erwartet = TRUE;
  i          = 2;

  while(befehl[i] != str_ende)
  {
    if (ziffer(befehl[i]))
    {
      /* Ziffer gefunden: Zahl vollstaendig lesen: */
      j = 0;
      loop:
        k[j] = befehl[i];
        if (!(ziffer(befehl[i+1]))) goto endloop;
        j++;
        i++;
        goto loop;
      endloop:
      k[j+1] = str_ende;
      /* k enthaelt jetzt die vollstaendige Zahl */

      sscanf(k,"%d",&zahl);

      if (x_erwartet)          /* x-Koordinate erwartet: */
      {
        if (absolut)
          x = zahl;
        else
          x = xalt + zahl;
        x_erwartet = FALSE;
      }
      else                     /* y-Koordinate erwartet: */
      {
        if (absolut)
          y = zahl;
        else
          y = yalt + zahl;
        if (stift_unten)
          schreiben(xalt,yalt,x,y);
        xalt = x;
        yalt = y;
        x_erwartet = TRUE;
      }
    }
    else
    {
      if (befehl[i] == 'P')
      {
        i++;
        switch (befehl[i])
        {
          case 'U': stift_unten = FALSE;   /* integrierter PU-Befehl */
                    break;
          case 'D': stift_unten = TRUE;    /* integrierter PD-Befehl */
                    break;
          default : return(FALSE);
        }
      }
      else
      {
        /* Komma wird ueberlesen, alles andere ist falsch: */
        if (befehl[i] != ',') return(FALSE);
      }
    }
    i++;
  }
  return(TRUE);
}


/*-------------------------------------------------------------------------*/
/*                       PU- oder PD-Befehl verarbeiten                    */
/*-------------------------------------------------------------------------*/

int pupd (int down)

/* Der PU- oder PD-Befehl hat optional ein x-y-Zahlenpaar als Parameter;
   die Zahlen sind dann durch ein Komma getrennt */
{
  int  x,y;
  char c;

  stift_unten = down;
  if (laenge > 2)  /* Koordinaten angegeben */
  {
    if (sscanf(befehl,"%c %c %d %c %d",&c, &c, &x, &c,&y) != 5)
      return(FALSE);
    if (stift_unten)
      schreiben(xalt,yalt,x,y);
    xalt = x;
    yalt = y;
  }
  return(TRUE);
}


/*-------------------------------------------------------------------------*/
/*                     In die Temporaerdatei schreiben                     */
/*-------------------------------------------------------------------------*/

void schreiben (int x1, int y1, int x2, int y2)
{
  /* Lebenszeichen auf Bildschirm: */
  zaehler++;
  if (zaehler == 10)
  {
    putchar('.');
    zaehler = 0;
  }

  /* Merken von Maximum und Minimum zur spaeteren Skalierung: */
  if (x1 < xmin) xmin = x1;
  if (x1 > xmax) xmax = x1;
  if (x2 < xmin) xmin = x2;
  if (x2 > xmax) xmax = x2;
  if (y1 < ymin) ymin = y1;
  if (y1 > ymax) ymax = y1;
  if (y2 < ymin) ymin = y2;
  if (y2 > ymax) ymax = y2;

  fwrite(&x1,sizeof(int),1,td);
  fwrite(&y1,sizeof(int),1,td);
  fwrite(&x2,sizeof(int),1,td);
  fwrite(&y2,sizeof(int),1,td);
}


/*-------------------------------------------------------------------------*/
/*                     Aus der Temporaerdatei lesen                        */
/*-------------------------------------------------------------------------*/

int lesen (int *x1ptr, int *y1ptr, int *x2ptr, int *y2ptr)
{
  /* Lebenszeichen auf Bildschirm: */
  zaehler++;
  if (zaehler == 10)
  {
    putchar('.');
    zaehler = 0;
  }

  if (!fread(x1ptr,sizeof(int),1,td)) return(FALSE);
  if (!fread(y1ptr,sizeof(int),1,td)) return(FALSE);
  if (!fread(x2ptr,sizeof(int),1,td)) return(FALSE);
  if (!fread(y2ptr,sizeof(int),1,td)) return(FALSE);

  return(TRUE);
}


/*-------------------------------------------------------------------------*/
/*                      Ausgabe in die METAFONT-Datei                      */
/*-------------------------------------------------------------------------*/

void ausgabe(void)
{
  int   x1,y1,x2,y2;
  float xmaxmm,x1mm,y1mm,x2mm,y2mm,faktor;

  /* Ausdehnung der Zeichnung in mm:
  y-Ausdehnung ist vorgegeben (=ysoll), x-Ausdehnung wird berechnet: */
  xmaxmm = ysoll * (float)(xmax-xmin) / (float)(ymax-ymin);

  printf("\n\n- Schreibe METAFONT-Datei \"%s\"\n",mfdatei);
  
  /* Initialisierungsteil der METAFONT-Datei: */
  md = fopen(mfdatei, "w");
  fprintf(md,"%% METAFONT-Quelltext %s, erzeugt aus %s\n",mfdatei,hpdatei);
  fprintf(md,"mode_setup;\n");
  fprintf(md,"beginchar(\"Z\",%4.3fmm#,%4.3fmm#,0);\n",xmaxmm,ysoll);
  fprintf(md,"pickup pencircle scaled 0.3mm;\n");

  /* Faktor zur Transformation der Koordinaten in Millimeter: */
  faktor = ysoll / ((float)(ymax-ymin));

  /* Lesen der Temporaerdatei mit den gespeicherten Koordinaten: */
  td = fopen(tddatei,"rb");

  zaehler = 0;

  while (lesen(&x1,&y1,&x2,&y2))
  {
    /* Transformation der Koordinaten in Millimeter: */
    x1mm = (float)(x1-xmin) * faktor;
    y1mm = (float)(y1-ymin) * faktor;
    x2mm = (float)(x2-xmin) * faktor;
    y2mm = (float)(y2-ymin) * faktor;

    /* Schreiben in die METAFONT-Datei: */
    fprintf(md,"draw (%4.3fmm,%4.3fmm)--(%4.3fmm,%4.3fmm);\n",
            x1mm,y1mm,x2mm,y2mm);
  }

  /* METAFONT-Datei abschliessen: */
  fprintf(md,"endchar;\n");
  fprintf(md,"end;\n");
  fclose(md);

  /* Temporaerdatei schliessen und loeschen: */
  fclose(td);
  remove(tddatei);

  printf("\n");
}
