/*-------------------------------------------------------------------------*/
/*                                                                         */
/* 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");
}