/*********************************************************************
*                                                                    *
*                           DVIPrintSetUp                            *
*                                                                    *
*                   Version 3.86 vom 30. Mai 1993                    *
*                   geschrieben von Stefan Scherer                   *
*                                                                    *
*         > > > >     Läuft nur ab Kickstart V37      < < < <        *
*                                                                    *
*  Dieses Programm soll den Umgang mit DVIprint erleichtern.  Das    *
*  Passauer TeX enthält eine ARexx-Schnittstelle, mit der man sehr   *
*  komfortabel arbeiten kann.  Der Ausdruck von Seiten jedoch war    *
*  bisher etwas umständlich (Abfrage mit OK / Cancel).  Dieses       *
*  Setup-Programm stellt nun die Druckoptionen für DVIprint          *
*  mit Hilfe einer grafischen Benutzeroberfläche ein.                *
*                                                                    *
**********************************************************************
*                                                                    *
*  AUTOR: Stefan Scherer                                             *
*         Abt-Wolf-Straße 17                                         *
*         8620 Lichtenfels (ab 1. Juli 1993: 96215)                  *
*         Tel.: 09571/2013                                           *
*                                                                    *
*  Änderungswünsche, Hinweise und Fehlerbeschreibungen werden gerne  *
*  entgegen genommen und falls möglich eingearbeitet.                *
*                                                                    *
**********************************************************************
*                                                                    *
*  COPYRIGHT: Dieses Programm und der zugeh"orige Quellcode sind     *
*                                                                    *
*                       >>>  FREEWARE  <<<                           *
*                                                                    *
*  und damit (c) Copyright 1992, 1993, Stefan Scherer.               *
*  S"amtliche Urheberrechte bleiben beim Autor.                      *
*                                                                    *
*  Der Vertrieb des unveränderten Programmes, einschließlich der     *
*  vorhandenen Dokumentation und des unveränderten Quellcodes ist    *
*  zulässig, sofern dieser Urheberrechtsvermerk bei allen Kopien     *
*  erhalten bleibt.                                                  *
*                                                                    *
*  Der Vertrieb von veränderten Versionen dieses Programmes ist      *
*  zulässig, sofern bei allen hiervon abgeleiteten Werken ein mit    *
*  obigem Hinweis vergleichbarer beigefügt wird.                     *
*                                                                    *
**********************************************************************
*                                                                    *
*  AUFRUF:  DVIPrintSetUp [<Seitennummer> [<DVI-File>]]              *
*                                                                    *
*  Es wird versucht, ein Window auf dem Screen von ShowDVI zu        *
*  öffnen, andernfalls wird das Window auf dem aktuellen Public      *
*  Screen geöffnet (meist die Workbench).                            *
*                                                                    *
*  Nachdem das Window geöffnet wurde, ist sofort das Gadget "From"   *
*  aktiviert, damit man sofort die Seitennummern eingeben kann.      *
*  (Hinweis: Mit Tabulator kann man zwischen den Gadgets wechseln)   *
*                                                                    *
*  Es stehen auch noch andere Gadgets für Einstellungen zur          *
*  Verfügung.  Dies sind der Druckoffset, der Drucker selbst         *
*  und verschiedene Optionen für den Ausdruck.                       *
*                                                                    *
*  Neu dazugekommen ist auch zwei Gadgets, mit denen man die         *
*  Druckumlenkung steuern kann.  Entweder man gibt direkt den        *
*  Filenamen der Datei an, in die "gedruckt" werden soll, oder man   *
*  wählt per Filerequester die Datei aus.                            *
*  Ist das String-Gadget "OutTo" leer, so wird die Ausgabe an den    *
*  Drucker geleitet.                                                 *
*  (Hinweis: Um den Dateinamen im "OutTo" Gadget schnell zu löschen, *
*            wählt man das Gadget an und drückt CTRL-X.)             *
*                                                                    *
*  Am unteren Rand des Windows befinden sich vier Gadgets:           *
*                                                                    *
*  SAVE  : Speichert die Einstellungen (außer Pages/From/To/OutTo)   *
*          in der Datei "TeX:config/DVIPrintSetUp.config" ab.        *
*  LOAD  : Lädt die gespeicherten Einstellungen aus der Datei        *
*          "TeX:config/DVIPrintSetUp.config" ein.  Dabei werden      *
*          die Werte Pages/From/To/OutTo nicht verändert.            *
*  PRINT : Startet das Programm "TeX:bin/DVIprint" mit den           *
*          aktuellen Parametern.  (Returncode = 0).                  *
*  CANCEL: Bricht das Programm ab.  (Returncode = 5).                *
*                                                                    *
**********************************************************************
*                                                                    *
* Bekanntes PROBLEM:                                                 *
*                                                                    *
*    DVIprint verträgt keine Leerzeichen im Dateinamen OutTo.  Der   *
*    Versuch, den Filenamen mit Anführungszeichen zu umklammern      *
*    scheiterte jedoch auch.  Also Vorsicht bei der Dateiauswahl.    *
*    Die einzige Abfrage in diesem Programm mache ich bei der        *
*    Auswahl des Dateinamens per ASL-Filerequester.  Hier wird       *
*    nämlich die Ram-Disk als "Ram Disk:" ausgewählt.  Dieser        *
*    String wird erkannt und durch "ram:" ersetzt.                   *
*                                                                    *
**********************************************************************
*                                                                    *
* NEU ab V3.84:                                                      *
*                                                                    *
*    Es wird nun zusätzlich zur Konfigurationsdatei eine             *
*    Environment-Variable "DVIPRINTSETUP" benutzt. Diese wird immer  *
*    mit dem Start eines Ausdrucks neu gesetzt. Beim Start von       *
*    DVIprintSetup wird die Variable zuerst eingelesen. Ist sie      *
*    nicht vorhanden, wird die Konfiguration eingelesen.             *
*                                                                    *
*    Sinn und Zweck:                                                 *
*    Die Environment-Variable sollte NICHT in EnvArc: existieren     *
*    oder anderweitig beim Start der TeX-Umgebung bereits gesetzt    *
*    werden. Die Variable wird benutzt, um aktuell eingestellte      *
*    Werte zwischenzuspeichern.                                      *
*    Beim ersten Start von DVIprintSetup wird die Konfiguration      *
*    eingelesen, bei jedem weiteren Aufruf wird die Environment-     *
*    Variable gelesen.                                               *
*                                                                    *
*    Beispiel:                                                       *
*    Man hat die Druckoffsets normalerweise auf 1in / 0.1in einge-   *
*    stellt. Nun möchte man kurz einen Brief drucken, wobei man      *
*    den vertikalen Offset auf 0.9in setzen muß. Nach dem Ausdruck   *
*    merkt man, daß irgendwo noch ein Druckfehler ist. Gut: Ändern,  *
*    TeX aufrufen und DVIprintSetup neu starten, schnell auf Print   *
*    geklickt und da hat man den Salat. Der Offset steht wieder auf  *
*    0.1in und man hat ihn vergessen erneut umzustellen.             *                                                                *
*    Durch die Environment-Variable tritt der Fehler nicht mehr auf. *
*    Möchte man später wieder auf die originalen Werte zurücksetzen, *
*    so klickt man nur auf Load.                                     *
*                                                                    *
*********************************************************************/

/* ------------------------------ Includes --------------------------------- */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/classes.h>
#include <intuition/classusr.h>
#include <intuition/imageclass.h>
#include <intuition/gadgetclass.h>
#include <dos/dostags.h>
#include <dos/dos.h>
#include <libraries/gadtools.h>
#include <graphics/displayinfo.h>
#include <clib/dos_protos.h>
#include <clib/exec_protos.h>
#include <clib/intuition_protos.h>
#include <clib/graphics_protos.h>
#include <clib/gadtools_protos.h>
#include <clib/utility_protos.h>
#include <clib/asl_protos.h>
#if defined(LATTICE) || defined(__SASC)
   int CXBRK(void) { return(0); }
   int chkabort(void) { return(0); }
#endif
#include "DVIPrintSetUp_rev.h"		/* Versionsstrings */
#include "DVIPrintSetUp_gad.h"		/* GadTools Definitionen und Prototypes */

/* ----------------------------- Prototypes -------------------------------- */

void main(int, char **);
BOOL HandleGadgetEvent(struct Window *, struct Gadget *, UWORD);
BOOL HandleVanillaKey(struct Window *, struct Gadget *, UWORD);
void CloseAll(int , STRPTR );
void SetEnv( BOOL );
BOOL GetEnv( void );
void SetGadgets( void );
void exit( int );
char *such_text(char [],char []);
BOOL IsNotSpace( char *);
void OnlineHelp( void );
void ParseEnv( void );
void ReadFile( BOOL );
void SaveFile( void );
void CheckGadgets( void );
void GetHOffset( void );
void GetVOffset( void );
void GetFromPage( void );
void GetToPage( void );
int SearchUnit( char * );

/* ---------------------- Variablen für Libraries -------------------------- */

#define PROGRAMNAME "TeX:bin/DVIprint " /* Leerzeichen, da Argumente folgen */
#define OUTWINDOW "CON:20/30/530/100/DVIprint--Output/CLOSE/SCREENShowDVI-PubScr"
#define FILENAME "TeX:config/DVIPrintSetUp.config"
#define ENVLENGTH 512                  /* Größe des Puffers */
#define PFADLENGTH 256
STRPTR ver = VERSTAG;                  /* Versionstring */
char SetupName[] = VERS;
extern struct Library *SysBase;
struct IntuitionBase *IntuitionBase = NULL;
struct GfxBase *GfxBase = NULL;
struct Library *GadToolsBase = NULL;
struct Library *UtilityBase = NULL;
struct Library *AslBase = NULL;

/* ------------------------ sonstige Variablen ----------------------------- */

BOOL doprint     = FALSE;		/* doprint = TRUE -> Drucken                */
BOOL terminated  = FALSE;		/* terminated = TRUE -> Programmende        */
int returncode   = RETURN_OK; /* Return code                              */
char envbuff[ENVLENGTH];		/* Puffer für Parameter                     */
char s[30];							/* Umwandlung ASCII->Float                  */
char pfad[PFADLENGTH];			/* Puffer für Outfile */
double zahl;
struct Node *PrinterNode;
struct FileRequester *FileRequester = NULL;
STRPTR Printfile = NULL;		/* Zeiger auf DVI-Filename                  */

/* ---------------- Variablen für die Druckeinstellungen ------------------- */

int Printer      = 0;			/* Voreingestellt auf NECP6 (siehe Liste)   */
char HOffset[12] = { "1" };	/* horizontalen Offset auf 1in setzen       */
char VOffset[12] = { "1" };	/* vertikalen Offset auf 1in setzen         */
long int From    = 1;			/* Seitennummer                             */
long int To      = 1;			/* Seitennummer                             */
int hunitcount   = 0;			/* Zähler für Einheiten horizontaler Offset */
int vunitcount   = 0;			/* Zähler für Einheiten vertikaler Offset   */
int pagemode     = 0;			/* Zähler für All | Even | Odd              */
BOOL IffOutput   = FALSE;		/* Grundeinstellungen der Checkbox Gadgets  */
BOOL Landscaped  = FALSE;
BOOL FastPrint   = FALSE;
BOOL Optimize    = TRUE;
BOOL Unidirect   = TRUE;
BOOL SkipFF      = FALSE;
BOOL NoLogfile   = FALSE;
BOOL DraftMode   = FALSE;
BOOL Reverse     = FALSE;
BOOL Preload     = FALSE;
STRPTR OutTo     = NULL;

/* -------------------- Taglist für den Filerequester ---------------------- */

#ifndef ASLFR_Window
#define ASLFR_Window ASL_Window
#define ASLFR_Flags1 ASL_FuncFlags
#define FRF_DOPATTERNS FILF_PATGAD
#define ASLFR_InitialPattern ASL_Pattern
#define ASLFR_TitleText ASL_Hail
#define fr_Drawer rf_Dir
#define fr_File rf_File
#endif

struct TagItem AslTags[] = {
	ASLFR_Window, NULL,
	ASLFR_Flags1,FRF_DOPATTERNS,
	ASLFR_InitialPattern,(ULONG)"#?.par",
	ASLFR_TitleText,(ULONG)"Select output file",
	TAG_DONE
	};

struct TagItem PrintTags[] = {
	SYS_Input, NULL,
	SYS_Output, NULL,
	TAG_DONE
	};

/* -------------- Struktur für Requester bei Fehlermeldungen --------------- */

struct EasyStruct ErrorRequester = {
	sizeof (struct EasyStruct),
	0,
	"Fehlermeldung",
	"%s",
	"Schade"
	};

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

/*  such_text()
 *
 *  Suchen nach einer Zeichenkette in einer anderen Zeichenkette
 *  Wurde die Zeichenkette gefunden, so wird die Position zurückgegeben.
 *  Andernfalls wird 0 zurückgegeben.
 */

char *such_text( char kette[], char teil[] )
{
	int i, j, k;
	char *zeiger = kette;
	for (i=0; kette[i] != '\0'; i++, zeiger++) {
		for (j=i,k=0; teil[k] != '\0' && kette[j] == teil[k]; j++, k++);
		if (teil[k] == '\0')
			return(zeiger);
	}
	return( 0 );
}

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

/*  IsNotSpace()
 *
 *  Überprüft, ob eine Zeichenkette nur aus Leerzeichen besteht.  Wenn nicht,
 *  wird TRUE zurückgegeben, andernfalls FALSE.
 */

BOOL IsNotSpace( char *kette )
{
	if (!kette) return(FALSE);
	else
		while (*kette == ' ')
			kette++;
	return((BOOL)(*kette != '\0'));
}

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

/*  main()
 *
 *  Das Hauptprogramm.  Hier werden zuerst alle Libraries geöffnet, danach
 *  das Window und alle Aktionen des Benutzers bearbeitet.  Main ist vom
 *  Typ void, da in jedem Fall das Programm über
 */

void main( int argc, char *argv[] )
{
	struct IntuiMessage *imsg;
	struct Gadget *gad;
	ULONG imsgClass;
	UWORD imsgCode;

	/* OS2.0 vorhanden, dann alle Libraries öffnen */

	if (!(IntuitionBase = (struct IntuitionBase *)
		OpenLibrary("intuition.library", 37L)))
		CloseAll(RETURN_FAIL, "Benötigt V37 intuition.library");
	if (!(GfxBase = (struct GfxBase *)
		OpenLibrary("graphics.library", 37L)))
		CloseAll(RETURN_FAIL, "Benötigt V37 graphics.library");
	if (!(GadToolsBase = OpenLibrary("gadtools.library", 37L)))
		CloseAll(RETURN_FAIL, "Benötigt V37 gadtools.library");
	if (!(UtilityBase = OpenLibrary("utility.library", 37L)))
		CloseAll(RETURN_FAIL, "Benötigt V37 utility.library");
	if (!(AslBase = OpenLibrary("asl.library", 37L)))	/* sollte auch mit V37 laufen */
		CloseAll(RETURN_FAIL, "Benötigt V37 asl.library");

	/* Filerequester anfordern */

	if (! (FileRequester = AllocAslRequest(ASL_FileRequest, NULL)) )
		CloseAll(RETURN_FAIL, "Filerequester");

	/* falls Argument vorhanden, dieses als Seitennummer nehmen */

	if ( argc >= 2 )
		To = From = atol(argv[1]);

	if ( argc >= 3 )
		Printfile = argv[2];

	/*
	 *  Versuchen, ob die Environment-Variable "DVIPRINTSETUP" gesetzt ist
	 *  und gegebenenfalls die Daten einlesen. Wenn nicht, prüfen, ob die Datei
	 *  "TeX:config/DVIPrintSetUp.config" existiert.  Wenn
	 *  das nicht klappt, sind die vordefinierten Variablen gültig.
	 *  FALSE bedeutet, daß keine
	 *  Gadgets neu gezeichnet werden sollen, da noch keine existieren.
	 */

	if ( ! GetEnv() )
		ReadFile( FALSE );

	/*
	 *  Nun werden die beiden Unterprogramme von der GadToolsBox aufgerufen.
	 *  Zuerst wird der aktuelle PublicScreen "festgehalten", damit er nicht
	 *  in der Zwischenzeit geschlossen werden kann.  Danach wird das Window
	 *  geöffnet und alle Gadgets erscheinen am Bildschirm.
	 */

	if ( SetupScreen() )
		CloseAll(RETURN_FAIL, "Screen nicht gefunden");
	if ( OpenDVIPrintSetUpWindow() )
		CloseAll(RETURN_FAIL, "Window nicht installiert");

	/*
	 *  Adresse des eigenen Windows in die Taglist für den Filerequester
	 *  eintragen, da der Wert erst jetzt zur Verfügung steht.
	 */

	AslTags[0].ti_Data = (ULONG)DVIPrintSetUpWnd;

	/*
	 *  Nun ist alles am Bildschirm sichtbar und der Benutzer kann seine
	 *  Eingaben machen.  Da bei der Druckereinstellung am häufigsten nur
	 *  die Seitennummern geändert werden sollen, wird nun noch das Gadget
	 *  "GD_From" aktiviert, um dort sofort zu editieren.
	 */

	ActivateGadget(DVIPrintSetUpGadgets[GD_From], DVIPrintSetUpWnd, NULL);

	/*
	 *  Der nun folgende Teil ist zur Auswertung der Benutzereingaben
	 *  zuständig.  Das Programm wird beendet, wenn "terminated" auf TRUE
	 *  gesetzt wird.  Diesen Wert bekommt man aus jeder Unterroutine,
	 *  so daß im Prinzip auf jedes Ereignis hin das Programm beendet
	 *  werden kann.  (Dieser Teil des Programms kann mit dem Programm "Skew"
	 *  erzeugt werden, so daß wieder etwas Schreibarbeit entfallen kann.)
	 */

	while (!terminated) {
		Wait (1 << DVIPrintSetUpWnd->UserPort->mp_SigBit);

		while ((!terminated) && (imsg = GT_GetIMsg(DVIPrintSetUpWnd->UserPort))) {
			imsgClass = imsg->Class;
			imsgCode = imsg->Code;
			gad = (struct Gadget *)imsg->IAddress;
			GT_ReplyIMsg(imsg);

			switch (imsgClass) {
				case IDCMP_GADGETDOWN:
				case IDCMP_MOUSEMOVE:
				case IDCMP_GADGETUP:
					/*
					 *  es wurde eine Gadgetfunktion ausgeführt.
					 *  Dies kann das Anwählen eines Gadgets mit der Maus,
					 *  das Eingabeende bei String- und Integer-Gadgets
					 *  durch Return oder Tabulator, oder ähnliches sein.
					 */
					terminated = HandleGadgetEvent(DVIPrintSetUpWnd, gad, imsgCode);
					break;

				case IDCMP_VANILLAKEY:
					/*
					 *  eine Taste wurde betätigt.
					 *  Es können die meisten Gadgets per Tastenkürzel
					 *  aktiviert werden.
					 */
					terminated = HandleVanillaKey(DVIPrintSetUpWnd, gad, imsgCode);
					break;

				case IDCMP_CLOSEWINDOW:
					/*
					 *  CloseWindowButton wurde angeklickt.
					 *  Hier wird auch der returncode auf 5 gesetzt, da das
					 *  Setup-Programm meist im ARexx-Skript läuft und ein
					 *  Schließen des Windows einen Abbruch des Druckvorganges
					 *  bedeutet.
					 */
					terminated = TRUE;
					returncode = RETURN_WARN;
					break;

				case IDCMP_REFRESHWINDOW:
					/*
					 *  Falls das Window durch andere überdeckt wurde
					 *  und nun die Gadgets neu gezeichnet werden sollen,
					 *  wird hier alles vorgenommen.  Alle Gadgets werden
					 *  durch GT_BeginRefresh() aktualisiert.  Zusätzlich
					 *  wird auch ein weiteres Unterprogramm von der
					 *  GadToolsBox aufgerufen, das sonstige Texte neu
					 *  schreibt.
					 */
					GT_BeginRefresh(DVIPrintSetUpWnd);
					DVIPrintSetUpRender();
					GT_EndRefresh(DVIPrintSetUpWnd, TRUE);
					break;
				}
			/*
			 *  Zusätzlich ist zu (fast) jedem Zeitpunkt die Hilfefunktion
			 *  erreichbar.  Dazu kann der Benutzer die HELP-Taste drücken.
			 *  Ist dies der Fall (Help entspricht 0x5F), so wird die
			 *  Onlinehilfe gestartet.  (siehe DVIPrintSetUp_Help.c)
			 */

			if (imsgCode == 0x5F) {
				OnlineHelp();
				SetGadgets();
				}

			}
		}
	CloseAll(returncode, NULL);
}

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

/*  HandleGadgetEvent()
 *
 *  Hier werden alle Aktionen abgearbeitet, die direkt mit den
 *  Gadgets zu tun haben.  So wird gemeldet, wenn eines der ButtonGadgets
 *  angeklickt wurde oder wenn der Benutzer die Eingabe in einem
 *  String- oder Integer-Gadget beendet hat.  Bei all diesen Aktionen
 *  werden die aktuellen Zustände der Gadgets in die eigenen Variablen
 *  übernommen.
 */

BOOL HandleGadgetEvent( struct Window *win, struct Gadget *gad, UWORD code )
{
	BOOL terminated = FALSE;
	switch (gad->GadgetID)
	{
		case GD_Printer:
			/* Bei Auswahl eines Druckers Nummer merken */
			Printer = (int)code;
			break;

		case GD_HOffset:
			/*
			 *  Bei Eingabe des Offsets String in Zahl umwandeln
			 *  Zusätzlich wird die Zahl wieder in den String
			 *  umgewandelt, damit eventuelle Fehler bei der Eingabe
			 *  beseitigt werden.  Bei einer späteren HookFunc kann
			 *  der letzte Teil entfallen.
			 */
			GetHOffset();
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_HOffset], DVIPrintSetUpWnd, NULL, GTST_String, &s, TAG_DONE );
			break;

		case GD_VOffset:
			/* Bei Eingabe des Offsets String in Zahl umwandeln */
			GetVOffset();
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_VOffset], DVIPrintSetUpWnd, NULL, GTST_String, &s, TAG_DONE );
			break;

		case GD_Pages:
			/* Auswahl des Seitenmodus mit Cycle-Gadget, Nummer merken */
			pagemode = (int)code;
			break;

		case GD_From:
			/*
			 *  Eingabe der Seitenzahl, Seitennummer merken
			 *  Bei Null noch nachsehen, ob überhaupt ein String
			 *  eingegeben wurde.  Wenn nicht, dann Seitenanfang
			 *  auf -100000 setzen, das heißt keine Begrenzung vom
			 *  Beginn her.
			 */
			GetFromPage();
			break;

		case GD_To:
			/*
			 *  Eingabe der Seitenzahl, Seitennummer merken
			 *  Bei Null noch nachsehen, ob überhaupt ein String
			 *  eingegeben wurde.  Wenn nicht, dann Seitenende
			 *  auf 100000 setzen, das heißt keine Begrenzung zum
			 *  Ende hin.
			 */
			GetToPage();
			break;

		case GD_OutTo:
			/*
			 *  Eingabe im Gadget für die Druckumlenkung beendet.
			 *  Zeiger auf diesen String merken.  Später wird dann
			 *  nachgesehen, ob dieser String gültig für eine Umlenkung
			 *  des Druckvorganges in eine Datei ist.
			 */
			OutTo = ((struct StringInfo *)gad->SpecialInfo)->Buffer;
			break;

		case GD_Outfile:
			/*
			 *  Das Gadget für den Filerequester wurde angeklickt.
			 *  Daraufhin öffnet man den Asl-Filerequester und
			 *  läßt den Benutzer den Pfad und den Dateinamen auswählen.
			 *  Zusätzlich wird überprüft, ob die Datei in die "Ram Disk:"
			 *  geschrieben werden soll.  Wenn ja, dann muß der Devicename
			 *  in "ram:" umbenannt werden, da DVIprint KEINE Leerzeichen
			 *  bei Dateinamen beherrscht, auch nicht mit umklammernden
			 *  Anführungszeichen.
			 */
			if ( AslRequest(FileRequester, AslTags) ) {
				if ( such_text( FileRequester->fr_Drawer, "Ram Disk:" ) ) {
					strcpy( pfad, "ram" );
					strcat( pfad, strchr( FileRequester->fr_Drawer, ':') );
					}
				else
					strcpy( pfad, FileRequester->fr_Drawer );
				if ( AddPart( pfad, FileRequester->fr_File, PFADLENGTH ) ) {
					OutTo = pfad;
					GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_OutTo], DVIPrintSetUpWnd, NULL, GTST_String, OutTo, TAG_DONE );
					}
				}
			break;

		case GD_Save:
			/*
			 *  Das Save-Gadget wurde angeklickt.
			 *  Hier wird die Einstellung in der Datei
			 *  "TeX:config/DVIPrintSetUp.config" abgespeichert.
			 *  SetEnv() wird mit FALSE aufgerufen, um die Werte
			 *  From, To und Pages nicht mit in den String zu übernehmen.
			 *  Ich benötige den String nur zum Abspeichern.
			 */
			SaveFile();
			break;

		case GD_Load:
			/*
			 *  Das Load-Gadget wurde angeklickt.
			 *  Es soll die Grundeinstellung aus der Datei eingelesen
			 *  werden und die Gadgets neu eingestellt werden (TRUE).
			 */
			ReadFile( TRUE );
			break;

		case GD_Use:
			/*
			 *  Use-Gadget wurde angeklickt.
			 *  Jetzt geht's zum Drucken.  Ein Flag wird gesetzt
			 *  und später das Programm "TeX:bin/DVIprint" gestartet.
			 */

			CheckGadgets();

			doprint = TRUE;
			terminated = TRUE;
			break;

		case GD_Cancel:
			/*
			 *  Cancel wurde angeklickt.
			 *  Abbruch des Druckvorganges durch Returncode = 5
			 */
			returncode = RETURN_WARN;
			terminated = TRUE;
			break;

		/*
		 *  Die folgenden Gadgets sind nur Checkbox-Gadgets.
		 *  Sie können mit oder ohne Haken sein.  Der aktuelle
		 *  Stand wird in den einzelnen Variablen festgehalten, die
		 *  jeweils nur negiert werden.
		 */
		case GD_Iff:
			IffOutput = !IffOutput;
			break;
		case GD_Landscaped:
			Landscaped = !Landscaped;
			break;
		case GD_Fast:
			FastPrint = !FastPrint;
			break;
		case GD_Optimize:
			Optimize = !Optimize;
			break;
		case GD_Unidirect:
			Unidirect = !Unidirect;
			break;
		case GD_SkipFF:
			SkipFF = !SkipFF;
			break;
		case GD_NoLogfile:
			NoLogfile = !NoLogfile;
			break;
		case GD_Draft:
			DraftMode = !DraftMode;
			break;
		case GD_Reverse:
			Reverse = !Reverse;
			break;
		case GD_Preload:
			Preload = !Preload;
			break;
	}
	return(terminated);
}

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

/*  HandleVanillaKey()
 *
 *  Hier werden alle Tasten abgefragt, die von Intuition dem Programm mit
 *  IDCMP_VANILLAKEY übermittelt werden.  Die meisten Gadgets haben
 *  entsprechene Tastenkürzel, um sie anzuwählen.  Deshalb sieht dieses
 *  Unterprogramm ähnlich aus wie HandleGadgetEvent().
 */

BOOL HandleVanillaKey( struct Window *win, struct Gadget *gad, UWORD code )
{
	BOOL terminated = FALSE;
	switch (code) {
		case 'h':
		case 'H':
			/* Gadget für horizontalen Offset aktivieren */
			ActivateGadget(DVIPrintSetUpGadgets[GD_HOffset], win, NULL);
			break;

		case 'v':
		case 'V':
			/* Gadget für vertikalen Offset aktivieren */
			ActivateGadget(DVIPrintSetUpGadgets[GD_VOffset], win, NULL);
			break;

		case 'i':
			/* Seitenmodus [ All | Even | Odd ] auswählen */
			if ( ! Pages0Labels[++pagemode] )
				pagemode = 0;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Pages], win, NULL, GTCY_Active, pagemode, TAG_DONE );
			break;

		case 'f':
		case 'F':
			/* Integer-Gadget für Startseite aktivieren */
			ActivateGadget(DVIPrintSetUpGadgets[GD_From], win, NULL);
			break;

		case 't':
		case 'T':
			/* Integer-Gadget für Zielseite aktivieren */
			ActivateGadget(DVIPrintSetUpGadgets[GD_To], win, NULL);
			break;

		case 's':
		case 'S':
			/* Einstellung speichern (wie in HandleGadgetEvent) */
			SaveFile();
			break;

		case 'l':
		case 'L':
			/* Grundeinstellung laden (wie in HandleGadgetEvent) */
			ReadFile( TRUE );
			break;

		case 'p':
		case 'P':
			/* Print: aktuelle Einstellung benutzen */
			doprint = TRUE;
			terminated = TRUE;
			CheckGadgets();
			break;

		case 'c':
		case 'C':
			/* Cancel: Programmabbruch mit Returncode 5 */
			returncode = RETURN_WARN;
			terminated = TRUE;
			break;

		case 'o':
		case 'O':
			/* String-Gadget für Druckumlenkung aktivieren */
			ActivateGadget(DVIPrintSetUpGadgets[GD_OutTo], win, NULL);
			break;

		/*
		 *  Alle folgenden Tasten beziehen sich wieder auf die
		 *  Checkbox-Gadgets.  Die einzelnen Variablen werden
		 *  aktualisiert und das Gadget neu gesetzt.
		 */
		case 'I':
			/* Ausgabe als IFF-Datei */
			IffOutput = !IffOutput;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Iff], win, NULL, GTCB_Checked, IffOutput, TAG_DONE );
			break;

		case 'e':
		case 'E':
			/* um 90° gekippter Ausdruck */
			Landscaped = !Landscaped;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Landscaped], win, NULL, GTCB_Checked, Landscaped, TAG_DONE );
			break;

		case 'a':
		case 'A':
			/* Schneller Druckmodus */
			FastPrint = !FastPrint;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Fast], win, NULL, GTCB_Checked, FastPrint, TAG_DONE );
			break;

		case 'm':
		case 'M':
			/* Druck mit Optimierung */
			Optimize = !Optimize;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Optimize], win, NULL, GTCB_Checked, Optimize, TAG_DONE );
			break;

		case 'n':
			/* Unidirectional */
			Unidirect = !Unidirect;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Unidirect], win, NULL, GTCB_Checked, Unidirect, TAG_DONE );
			break;

		case 'N':
			/* kein Logfile anlegen */
			NoLogfile = !NoLogfile;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_NoLogfile], win, NULL, GTCB_Checked, NoLogfile, TAG_DONE );
			break;

		case 'k':
		case 'K':
			/* FormFeed weglassen */
			SkipFF = !SkipFF;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_SkipFF], win, NULL, GTCB_Checked, SkipFF, TAG_DONE );
			break;

		case 'd':
		case 'D':
			/* geringere Druckerauflösung */
			DraftMode = !DraftMode;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Draft], win, NULL, GTCB_Checked, DraftMode, TAG_DONE );
			break;

		case 'r':
		case 'R':
			/* Seiten rückwärts von To bis From ausgeben */
			Reverse = !Reverse;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Reverse], win, NULL, GTCB_Checked, Reverse, TAG_DONE );
			break;

		case 'g':
		case 'G':
			/* alle Fonts am Anfang einlesen */
			Preload = !Preload;
			GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Preload], win, NULL, GTCB_Checked, Preload, TAG_DONE );
			break;
		}
	return(terminated);
}

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

/*  SetEnv()
 *
 *  Stellt die Parameter für DVIprint mit den eingestellten
 *  Werten neu ein.  Durch TRUE wird alles in den String geschrieben.
 *  FALSE wird zum Speichern der Parameter benötigt.
 */

void SetEnv( BOOL mode )
{
	int i = 0;
	sprintf( envbuff, "HOFFSET=%s VOFFSET=%s", HOffset, VOffset );
	if ( mode ) {
		sprintf( s, " FROM %ld TO %ld", From, To );
		strcat( envbuff, s);
		}
	PrinterNode = (struct Node *)Printer0List.mlh_Head;
	while (i++ != Printer)
		PrinterNode = PrinterNode->ln_Succ;
	if (strcmp(PrinterNode->ln_Name, "generic")) {
		/* Zusatzabfrage, ob Landscape-Modus */
		if ((!strcmp(PrinterNode->ln_Name, "NECP6")) && (Landscaped))
			PrinterNode = PrinterNode->ln_Succ;
		strcat( envbuff, " PRINTER ");
		strcat( envbuff, PrinterNode->ln_Name );
		}
	if (mode && pagemode) {
		strcat( envbuff, " " );
		strcat( envbuff, Pages0Labels[pagemode] );
		}
	if (IffOutput)  strcat( envbuff, " IFF"    );
	if (Landscaped) strcat( envbuff, " LAND"   );
	if (FastPrint)  strcat( envbuff, " FAST"   );
	if (!Optimize)  strcat( envbuff, " OPT off");
	if (!Unidirect) strcat( envbuff, " UNI off");
	if (SkipFF)     strcat( envbuff, " SKIP"   );
	if (NoLogfile)  strcat( envbuff, " NOLOG"  );
	if (DraftMode)  strcat( envbuff, " DRAFT"  );
	if (Reverse)    strcat( envbuff, " REV"    );
	if (Preload)    strcat( envbuff, " PRE"    );
	if ( mode && IsNotSpace(OutTo) )
	{
		strcat( envbuff, " OUT " );
		strcat( envbuff, OutTo   );
	}
	if ( mode )
		SetVar( "DVIPRINTSETUP", envbuff, -1, GVF_GLOBAL_ONLY );
}

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

/*  GetEnv()
 *
 *  Liest die Parameter für DVIprint aus der Environment-Variable
 *  "DVIPRINTSETUP" ein.
 *  Im Fehlerfall wird FALSE zurückgegeben, andernfalls TRUE.
 */

BOOL GetEnv( void )
{
	BOOL success;

	if ( GetVar( "DVIPRINTSETUP", envbuff, ENVLENGTH, GVF_GLOBAL_ONLY ) == -1 )
		success = FALSE;
	else
	{
		ParseEnv();
		success = TRUE;
	}
	return( success );
}

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

/*  SetGadgets()
 *
 *  Stellt alle Gadgets auf die aktuellen Werte ein.  Für jedes Gadget
 *  muß GT_SetGadgetAttrs() aufgerufen werden.  Lange Variablennamen
 *  machen diesen Programmteil zum wahren "Klotz".
 */

void SetGadgets( void )
{
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Reverse], DVIPrintSetUpWnd, NULL, GTCB_Checked, Reverse, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Printer], DVIPrintSetUpWnd, NULL, GTLV_Selected, Printer, GTLV_Top, Printer, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_HOffset], DVIPrintSetUpWnd, NULL, GTST_String, HOffset, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_VOffset], DVIPrintSetUpWnd, NULL, GTST_String, VOffset, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Pages], DVIPrintSetUpWnd, NULL, GTCY_Active, pagemode, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Draft], DVIPrintSetUpWnd, NULL, GTCB_Checked, DraftMode, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Iff], DVIPrintSetUpWnd, NULL, GTCB_Checked, IffOutput, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Optimize], DVIPrintSetUpWnd, NULL, GTCB_Checked, Optimize, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Fast], DVIPrintSetUpWnd, NULL, GTCB_Checked, FastPrint, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Landscaped], DVIPrintSetUpWnd, NULL, GTCB_Checked, Landscaped, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Preload], DVIPrintSetUpWnd, NULL, GTCB_Checked, Preload, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_NoLogfile], DVIPrintSetUpWnd, NULL, GTCB_Checked, NoLogfile, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_SkipFF], DVIPrintSetUpWnd, NULL, GTCB_Checked, SkipFF, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_Unidirect], DVIPrintSetUpWnd, NULL, GTCB_Checked, Unidirect, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_From], DVIPrintSetUpWnd, NULL, GTIN_Number, From, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_To], DVIPrintSetUpWnd, NULL, GTIN_Number, To, TAG_DONE );
	GT_SetGadgetAttrs(DVIPrintSetUpGadgets[GD_OutTo], DVIPrintSetUpWnd, NULL, GTST_String, OutTo, TAG_DONE );
}

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

/*  ReadFile()
 *
 *  Hiermit werden die Grundeinstellungen aus der Datei
 *  "TeX:config/DVIPrintSetUp.config" eingelesen, die
 *  internen Variablen neu gesetzt und falls update TRUE
 *  ist auch die Gadgets neu gezeichnet.
 */

void ReadFile( BOOL update )
{
	BPTR datei;
	LONG len;

	if ( datei = Open( FILENAME, MODE_OLDFILE ) )
	{
		len = Read( datei, envbuff, ENVLENGTH );
		envbuff[len] = NULL;
		Close( datei );

		ParseEnv();

		if (update) SetGadgets();
	}
}

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

/*  ParseEnv()
 *
 *  Auswertung der eingelesenen Environment-Variable bzw. der gelesenen
 *  Konfigurationsdatei. Der String liegt bereits in envbuff. Es werden
 *  sämtlichen Variablen gesetzt. Falls das Fenster bereits geöffnet ist,
 *  müssen zusätzlich mit SetGadgets() alle Gadgets aktualisiert werden.
 */

void ParseEnv( void )
{
	STRPTR envpos;

	if (envpos = such_text( envbuff, "HOFFSET"))
	{
		envpos += 8;
		sscanf( envpos, "%12s", s);
		hunitcount = SearchUnit( s );
		zahl = atof( envpos );
		sprintf( s, "%1.4lf%s", zahl, UnitLabels[ hunitcount ] );
		strcpy(HOffset, s);
	}

	if (envpos = such_text( envbuff, "VOFFSET"))
	{
		envpos += 8;
		sscanf( envpos, "%12s", s);
		vunitcount = SearchUnit( s );
		zahl = atof( envpos );
		sprintf( s, "%1.4lf%s", zahl, UnitLabels[ vunitcount ] );
		strcpy(VOffset, s);
	}

	if (envpos = such_text( envbuff, "PRINTER"))
	{
		Printer = 0;
		PrinterNode = (struct Node *)Printer0List.mlh_Head;
		while ((PrinterNode != (struct Node *)&Printer0List.mlh_Tail) &&
             !(such_text( envpos, PrinterNode->ln_Name )))
		{
			PrinterNode = PrinterNode->ln_Succ;
			Printer++;
		}
	}
	pagemode = 0;
	if (such_text( envbuff, "Even" )) pagemode = 1;
	if (such_text( envbuff, "Odd"  )) pagemode = 2;
	if (such_text( envbuff, "IFF"  )) IffOutput = TRUE; else IffOutput = FALSE;
	if (such_text( envbuff, "LAND" )) Landscaped= TRUE; else Landscaped= FALSE;
	if (such_text( envbuff, "FAST" )) FastPrint = TRUE; else FastPrint = FALSE;
	if (such_text( envbuff, "SKIP" )) SkipFF    = TRUE; else SkipFF    = FALSE;
	if (such_text( envbuff, "NOLOG")) NoLogfile = TRUE; else NoLogfile = FALSE;
	if (such_text( envbuff, "DRAFT")) DraftMode = TRUE; else DraftMode = FALSE;
	if (such_text( envbuff, "REV"  )) Reverse   = TRUE; else Reverse   = FALSE;
	if (such_text( envbuff, "PRE"  )) Preload   = TRUE; else Preload   = FALSE;
	if (such_text( envbuff, "UNI off")) Unidirect = FALSE; else Unidirect = TRUE;
	if (such_text( envbuff, "OPT off")) Optimize  = FALSE; else Optimize  = TRUE;
}

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

/*  SaveFile()
 *
 *  Hiermit werden die Grundeinstellungen in die Datei
 *  "TeX:config/DVIPrintSetUp.config" gespeichert.
 */

void SaveFile( void )
{
	BPTR datei;
	SetEnv( FALSE );
	if ( datei = Open( FILENAME, MODE_NEWFILE ) ) {
		Write( datei, envbuff, strlen(envbuff) );
		Close( datei );
	}
}

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

/*  CloseAll()
 *
 *  Hiermit wird das Programm beendet.  Zuerst wird alles geschlossen,
 *  was zu Beginn geöffnet wurde.  Falls ein Fehlerstring mit übergeben
 *  wird, wird dieser per Requester angezeigt.  Das Programm wird mit
 *  dem Returncode "code" beendet.
 */

void CloseAll( int code, STRPTR error )
{
	char commbuff[ENVLENGTH];
	BPTR outcon;

	/* Schließen der grafischen Benutzeroberfläche (GUI) */
	CloseDVIPrintSetUpWindow();
	CloseDownScreen();

	/* Filerequester freigeben */
	if (FileRequester) FreeFileRequest( FileRequester );

	/* Libraries schließen */
	if (AslBase)      CloseLibrary(AslBase);
	if (UtilityBase)  CloseLibrary(UtilityBase);
	if (GadToolsBase) CloseLibrary(GadToolsBase);
	if (GfxBase)      CloseLibrary((struct Library *)GfxBase);

	/*
	 *  Besonderheit bei intuition.library:
	 *  Falls ein Fehler vorliegt, wird dieser in einem
	 *  Requester angezeigt.
	 */
	if (IntuitionBase) {
		if (error)
			EasyRequestArgs( NULL, &ErrorRequester, NULL , &error );
		CloseLibrary((struct Library *)IntuitionBase);
	}

	/*
	 *  Hier wird nur noch die dos.library benötigt.
	 *  Diese wird vom Startup-Code geöffnet und steht hier noch zur
	 *  Verfügung.  Falls doprint gesetzt wurde, wird mit System() das
	 *  Programm DVIprint gestartet.
	 */
	if ( doprint )
	{
		SetEnv( TRUE );
		if (outcon = Open( OUTWINDOW, MODE_OLDFILE ))
		{
			PrintTags[0].ti_Data = outcon;
		/*	Write( outcon, envbuff, strlen(envbuff) ); */
			strcpy( commbuff, PROGRAMNAME );
			strcat( commbuff, envbuff );
			strcat( commbuff, " " );
			if ( Printfile )
			{
				strcat( commbuff, Printfile );
				code = System( commbuff, PrintTags );
			}
			Close( outcon );
		}
		else code = RETURN_ERROR;
	}
	exit(code);
}

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

/*  SearchUnit()
 *
 *  Sucht den angegebenen String nach den verschiedenen Maßeinheiten ab.
 *  Wird das Maß gefunden, wird die Nummer zurückgegeben (0...n-1).
 *  Wird nichts gefunden, wird 0 (default) zurückgegeben.
 */

int SearchUnit( char *buffer )
{
	int i = 0;

	while( UnitLabels[i] && ! such_text( buffer, UnitLabels[i] ) )
		i++;

	/* nichts gefunden, dann default auf 'in' */

	if ( ! UnitLabels[i] )
		i = 0;

	return( i );
}

/*  Auswertung der einzelnen String- und Integer-Gadgets
 *
 *  Nun als eigene Funktionen, da die Auswertung öfters benötigt wird.
 */

void GetHOffset( void )
{
	zahl = atof( ((struct StringInfo *)DVIPrintSetUpGadgets[GD_HOffset]->SpecialInfo)->Buffer );
	if ( zahl > 999.0 )
		zahl = 999.0;
	hunitcount = SearchUnit( ((struct StringInfo *)DVIPrintSetUpGadgets[GD_HOffset]->SpecialInfo)->Buffer );
	sprintf( s, "%1.4lf%s", zahl, UnitLabels[ hunitcount ] );
	strcpy(HOffset, s);
}

void GetVOffset( void )
{
	zahl = atof( ((struct StringInfo *)DVIPrintSetUpGadgets[GD_VOffset]->SpecialInfo)->Buffer );
	if ( zahl > 999.0 )
		zahl = 999.0;
	vunitcount = SearchUnit( ((struct StringInfo *)DVIPrintSetUpGadgets[GD_VOffset]->SpecialInfo)->Buffer );
	sprintf( s, "%1.4lf%s", zahl, UnitLabels[ vunitcount ] );
	strcpy(VOffset, s);
}

void GetFromPage( void )
{
	if ((From = ((struct StringInfo *)DVIPrintSetUpGadgets[GD_From]->SpecialInfo)->LongInt) == 0)
		if (! IsNotSpace( ((struct StringInfo *)DVIPrintSetUpGadgets[GD_From]->SpecialInfo)->Buffer ))
			From = -1000000;
}

void GetToPage( void )
{
	if ((To = ((struct StringInfo *)DVIPrintSetUpGadgets[GD_To]->SpecialInfo)->LongInt) == 0)
		if (! IsNotSpace( ((struct StringInfo *)DVIPrintSetUpGadgets[GD_To]->SpecialInfo)->Buffer ))
			To = 1000000;
}

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

/*  CheckGadgets()
 *
 *  Alle String- und Integer-Gadgets auslesen.
 */

void CheckGadgets( void )
{
	GetHOffset();
	GetVOffset();
	GetFromPage();
	GetToPage();
}
