/*
 *   Projekt zum formatierten Drucken
 *   unter Ausnutzung der Preferences-Struktur
 *   und wahlweisen InLine-Optionen
 */


/************************************
*                                   *
* PreProc-Anweisungen               *
* ===================               *
*                                   *
* Autor:    Datum:  Kommertar:      *
* ------    ------  ----------      *
* H.Kindler 23.7.91                 *
*                                   *
************************************/
#include <ctype.h>                  /* islower etc.  */
#include <stdlib.h>                 /* exit etc.     */
#include <stdio.h>                  /* printf etc.   */
#include <string.h>                 /* strlen etc.   */
#include <exec/types.h>             /* ULONG etc.    */
#include <exec/memory.h>            /* AvailMem etc. */
#include <intuition/intuition.h>    /* GetPrefs etc. */
#include <sys/stat.h>               /* stat etc.     */
#include <sys/time.h>               /* localtime etc.*/

#define DatumMax    25L                  /* Max. Stringlänge Datum        */
#define ESC         \33                  /* Esacpe-Zeichen                */
#define NUMLEN      6L                   /* Länge Zeilennummer (falls da) */
#define PRINT       9L                   /* Lg 1.Teil PrtFile (prt:Print) */
#define SIZE sizeof (struct Preferences) /* eine kleine Abkürzung         */
#define SKIP        7L                   /* Zeilen am Seitenende          */
#define TAB         8L                   /* Tabulatorgröße                */

void  Close_All    (void);                      /* Prototypen */
void  InitPrinter  (void);                      /* der        */
void  Open_All     (void);                      /* einzelnen  */
void  PrintEscape  (void);                      /* Funktionen */
short PrintKopf    (void);
short PrintLine    (short lines, short pline);
void  ResetPrinter (void);

short  CPL;                         /* Chars Per Line                  */
char   Datum [DatumMax];            /* Datum-String                    */
size_t DatumLen;                    /* Länge des Datum-Strings         */
BOOL   DoNum = FALSE;               /* (Keine) Zeilennummer            */
char   *FileName;                   /* Name, wie übergeben             */
FILE   *FP;                         /* FilePointer Eingabe-File        */
extern *IntuitionBase;              /* Intuition öffnen (DICE-Special) */
short  LPP;                         /* Lines Per Page                  */
short  LPI;                         /* Lines Per Inch                  */
short  LLen;                        /* LineLength (ohne Ränder)        */
BOOL   NoNum = FALSE;               /* ZN temporär unterdrücken (aus)  */
short  NumLen = 0;                  /* Länge der ZeilenNummer (ZN)     */
FILE   *PRT;                        /* FilePointer Drucker             */
struct Preferences *PrefsBuffer;    /* Prefs-Struktur                  */


/*******************************************
*                                          *
* Programm: Formatiertes Drucken von Files *
* ======================================== *
*                                          *
* Autor:    Datum:  Kommertar:             *
* ------    ------  ----------             *
* H.Kindler 23.7.91                        *
*                                          *
*******************************************/
void main (int argc, char **argv)
{
    short  c;                             /* var für fgetc              */
    short  i;                             /* Zählvariable               */
    short  anz   = 0;                     /* Zeichenzahl aktuelle Zeile */
    short  lines = 1;                     /* Zeilenzahl                 */
    short  pline = 0;                     /* Zeilen aktuelle Seite      */
    struct stat statbuf;                  /* Infos übers File           */
    time_t ftime;                         /* Datum des Files            */
    struct tm *tp;                        /* Time-Struct von ftime      */
    char   tmpnambuf [L_tmpnam];          /* Puffer PrtFile-tmpnam      */
    char   *prtname = "prt:Print";        /* Name für PrtFile           */
    char   prtfile [L_tmpnam + PRINT -2]; /* Fertiger Name              */

    FP = NULL;      /* File-Pointer auf NULL setzen (wird von */
    PRT = NULL;     /* Close_All() zur Auswertung gebraucht)  */

/*
 *    printf ("argc: %d\n",argc);
 *    for (i = 0; i < argc; ++i)
 *        printf ("argv[%d]: %s\n", i, argv[i]);
 */
    if ((argc < 2) ||                       /* eine kleine Hilfe */
        ((argc == 2) && (*argv[1] == '?')))
    {
        printf ("\33[33mAufruf:\33[31m\t\%s PrintFile [NUM]\n\n", argv[0]);
        puts ("Print druckt PrintFile (Wahlweise mit Zeilen-Nummerierung.)");
        puts ("Es werden zur Seitenformatierung automatisch die Werte");
        puts ("von Preferences benutzt.");
        puts ("\nMomentan kann statt NUM als dritter Wert etwas beliebiges");
        puts ("übergeben werden (\"Stinker\" tuts auch)!");
        exit (RETURN_OK);
    }
    if (argc == 3)   /* Momentan tut alles! */
    {
        DoNum = TRUE;       /* Nummerierung einschalten  */
        NumLen = NUMLEN;    /* Richtige Länge der Nummer */
    }
    Open_All ();
    FileName = argv[1];
    if (stat (FileName, &statbuf))          /* Infos übers File */
    {
        puts ("Error bei 'stat'");
        Close_All ();
        exit (RETURN_ERROR);
    }
    ftime = (time_t) statbuf.st_ctime;      /* Datum des Files */
    tp = localtime (&ftime);                /* Aufbereiten     */
    DatumLen = strftime (Datum, DatumMax, "%a %d.%b %Y  %H:%M:%S", tp);
/*
 *    printf ("Datum: %s\n Länge: %d\n", Datum, DatumLen);
 */
    if ((FP = fopen (FileName, "r")) == NULL)
    {
        printf ("Kann %s nicht öffnen!", argv[1]);
        Close_All ();
        exit (RETURN_ERROR);
    }
    strcpy (prtfile, prtname);              /* DruckName zusammenstellen */
    tmpnam (tmpnambuf);
    strcpy (prtfile + PRINT, tmpnambuf + 2);
    if ((PRT = fopen (prtfile, "w")) == NULL)
    {
        puts ("Kann Drucker nicht ansprechen!");
        Close_All ();
        exit (RETURN_ERROR);
    }
    InitPrinter();
    pline = LPP;                     /* Trick: Kopf 1.Seite und Anfang   */
    pline = PrintLine(lines, pline); /* 1. Zeile werden korrekt gedruckt */
    while ((c = fgetc (FP)) != EOF)
    {
        switch (c)
        {
            case '\n':                              /* NewLine           */
                lines++;                            /* neue Zeilennummer */
                pline = PrintLine (lines, pline);   /* neue Zeile        */
                anz = 0;                            /* ZeichenZähler = 0 */
                break;
            case '\f':                              /* FormFeed          */
                pline = PrintKopf ();               /* neue Seite        */
                anz = 0;                            /* ZeichenZähler = 0 */
                break;
            case '\t':                              /* Tabulator         */
                for (i = 0; i <= anz % TAB; i++)    /* Zeichen zum TAB   */
                    fputc (' ', PRT);               /* mit ' ' füllen    */
                anz += anz % TAB;                   /* Zähler stellen    */
                break;
            case '\33':             /* wird eigentlich nur gebraucht um  */
                fputc (c, PRT);     /* anz bei ESC-Sequencen nicht hoch- */
                PrintEscape ();     /* zuzählen (die Zeilen würden sonst */
                break;              /* zu kurz!)                         */
            default:
                if (anz++ == CPL)                     /* Falls Zeilenende */
                {
                    NoNum = TRUE;                     /* Zeilennummer aus */
                    pline = PrintLine (lines, pline); /* neue Zeile       */
                    NoNum = FALSE;                    /* Zeilennummer ein */
                    anz = 0;                          /* ZeichenZähler =0 */
                }
                fputc (c, PRT);                    /* einfach nur drucken */
        }
    }
    ResetPrinter ();
    Close_All ();
    exit (RETURN_OK);
}


/***********************************************
*                                              *
* Funktion: Alles Öffnen & Speicher            *
* =================================            *
*                                              *
* Autor:    Datum:  Kommertar:                 *
* ------    ------  ----------                 *
* H.Kindler 23.7.91 Nur Puffer für Perferences *
*                                              *
*                                              *
***********************************************/
void Open_All (void)
{
    UBYTE *AllocMem (ULONG size, ULONG requirements);

    PrefsBuffer = (struct Preferences *) AllocMem ((ULONG) SIZE, MEMF_CLEAR);     /*  Das gibt eine schöne, lange Zeile !!!!!! */
    if (!PrefsBuffer)
    {
        puts ("Kein Speicher frei!");
        Close_All ();
        exit (RETURN_ERROR);
    }
}


/***********************************************
*                                              *
* Funktion: Alles wieder schließen             *
* ================================             *
*                                              *
* Autor:    Datum:  Kommertar:                 *
* ------    ------  ----------                 *
* H.Kindler 23.7.91 Preferences, File, Drucker *
*                                              *
***********************************************/
void Close_All (void)
{
    void FreeMem (ULONG *memory, ULONG size);

    if (PrefsBuffer) FreeMem ((ULONG *) PrefsBuffer, (ULONG) SIZE);
    if (FP)  fclose (FP);
    if (PRT) fclose (PRT);
}


/*******************************
*                              *
* Funktion: Kopf drucken       *
* =====================        *
*                              *
* Autor:    Datum:  Kommentar: *
* ------    ------  ---------- *
* H.Kindler 24.7.91            *
*                              *
*******************************/
short PrintKopf ()
{
    static short len;           /* Länge der Teile der Kopfzeile   */
    static short fill;          /* das fehlt noch zur vollen Zeile */
    static short filla;         /* zwischen Datum und FileName     */
    static short fillb;         /* zwischen FileName und Seiten    */
    static short page = 0;      /* Seitenzahl                      */
    short i;                    /* Zähler                          */

    if (page)                                    /* Falls ! 1.Seite  */
        fputc ('\f', PRT);                       /* FormFeed         */
    else                                         /* sonst            */
    {                                            /* SPACE berechnen  */
        len = DatumLen + strlen (FileName) + 10; /*   Chars für Kopf */
        fill = LLen - len;                       /*   restliche Char */
        filla = fill / 2;                        /*   die Hälfte     */
        fillb = fill - filla;                    /*   und der Rest   */
    }
    page++;                                      /* eine Seite mehr  */
    fprintf (PRT, "%s", Datum);                  /* Datum            */
    for ( i = 1; i <= filla; i++)                /* Zwischenraum     */
        fputc (' ', PRT);
    fprintf (PRT, "%s", FileName);               /* FileName         */
    for ( i = 1; i <= fillb; i++)                /* Zwischenraum     */
        fputc (' ', PRT);
    fprintf (PRT, "Page: %4d\n\n\n", page);      /* Seitennummer     */
    return (3);                                  /* so viele Zeilen  */
}


/***************************************
*                                      *
* Funktion: Zeilenvorschub drucken     *
* ================================     *
*                                      *
* Autor:    Datum:  Kommentar:         *
* ------    ------  ----------         *
* H.Kindler 24.7.91 am Blattende: Kopf *
*                                      *
***************************************/
short PrintLine (short lines,      /*  Anzahl der '\n' im File         */
                 short pline)      /*  Auf dieser Seite gedruckte '\n' */
{
    if (pline++ < LPP)                      /* Falls Seite nicht voll */
        fputc ('\n', PRT);                  /* neue Zeile             */
    else                                    /* sonst                  */
        pline = PrintKopf ();               /* neue Seite             */
    if (DoNum)                              /* Falls Zeilennummern    */
        if (NoNum)                          /* Falls unterdrücken     */
            fputs ("      ", PRT);          /* Space drucken          */
        else                                /* sonst                  */
            fprintf (PRT, "%04d: ", lines); /* Zeilennummer drucken   */
    return (pline);                         /* so viele Zeilen        */
}


/*********************************
*                                *
* Funktion: ESC-Sequence drucken *
* ============================== *
*                                *
* Autor:    Datum:  Kommentar:   *
* ------    ------  ----------   *
* H.Kindler 26.7.91              *
*                                *
*********************************/
void PrintEscape (void)
{
    short c;

    c = fgetc (FP);           /* Ein Zeichen folgt immer */
    fputc (c, PRT);
    switch (c)
    {
        case '#':             /* hier folgt jeweils noch */
        case '(':             /* ein Zeichen             */
            c = fgetc (FP);
            fputc (c, PRT);
            break;
        case '[':             /* begrenzt durch E,F,g,m,p,q,r,s,v,w,x,z */
            while (!((islower (c = fgetc (FP)) || (c == 'E') || (c == 'F'))))
            {
                fputc (c, PRT);
            }
            fputc (c, PRT);
    }
    return ();
}


/******************************************
*                                         *
* Funktion: Drucker vorbereiten           *
* =============================           *
*                                         *
* Autor:    Datum:  Kommentar:            *
* ------    ------  ----------            *
* H.Kindler 25.7.91 Werte von Preferences *
*                                         *
******************************************/
void InitPrinter (void)
{

    struct Preferences *GetPrefs (struct Preferences *preferences, short size);

    short  lm;           /* Left Margin  */
    short  rm;           /* Right Margin */
    short  ppl;          /* PaPerLength  */

    GetPrefs (PrefsBuffer, (short) SIZE);
    switch (PrefsBuffer->PrintPitch)     /* Zeilenlänge festlegen */
    {
        case PICA:
            LLen = 80;
            break;
        case ELITE:
            LLen = 96;
            break;
        case FINE:
            LLen = 136;
            break;
        default:
            puts ("Hier läuft was falsch! (Schriftbreite)");
            Close_All ();
            exit (RETURN_WARN);
    }
    switch (PrefsBuffer->PrintSpacing)  /* Zeilen pro Zoll */
    {
        case SIX_LPI:
            LPI = 6;
            break;
        case EIGHT_LPI:
            LPI = 8;
            break;
        default:
            puts ("Hier läuft was falsch! (Zeilenabstand)");
            Close_All ();
            exit (RETURN_WARN);
    }
/*
 *    switch (PrefsBuffer->PaperSize)
 *    {
 *        case US_LETTER:
 *            puts ("US_LETTER");
 *            break;
 *        case US_LEGAL:
 *            puts ("US_LEGAL");
 *            break;
 *        case N_TRACTOR:
 *            puts ("N_TRACTOR");
 *            break;
 *        case W_TRACTOR:
 *            puts ("W_TRACTOR");
 *            break;
 *        case CUSTOM:
 *            puts ("CUSTOM");
 *            break;
 *        default:
 *            puts ("Hier läuft was falsch!");
 *            Close_All ();
 *            exit (RETURN_WARN);
 *    }
 */
    ppl = PrefsBuffer->PaperLength;         /* Papierlänge       */
    LPP = ppl - SKIP;                       /* so viel bedrucken */
    lm = PrefsBuffer->PrintLeftMargin - 1;  /* Ränder            */
    rm = PrefsBuffer->PrintRightMargin;
    if (rm > LLen)
        puts ("Achtung! Rechter Rand zu groß!!");
    LLen = rm - lm;                         /* Platz zw. Rändern    */
    CPL  = LLen - NumLen;                   /* weniger Nummernlänge */
    fputs ("\33#1", PRT);          /* Drucker vom System initialisieren  */
    fprintf(PRT, "\33[%dt", ppl);  /* Seitenlänge (System macht's nicht) */
    return();
}


/********************************
*                               *
* Funktion: Drucker verlassen   *
* ===========================   *
*                               *
* Autor:    Datum:  Kommentar:  *
* ------    ------  ----------  *
* H.Kindler 25.7.91             *
*                               *
********************************/
void ResetPrinter (void)
{
    fputs ("\f\33c", PRT);     /* FF, RESET */
    return ();
}

