
/* PRINT 1.3   (c) 5/90 Uli Bubenheimer */

/* Die Kommentare geben an, an welchen Stellen der Quellcode fuer die serielle Version
   von PRINT geaendert werden muss. */

#include <ctype.h> 
#include <exec/types.h>
#include <exec/memory.h>
#include <exec/alerts.h>
#include <stdio.h>
#include <fcntl.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <functions.h>
#include <intuition/intuition.h>

#define FEHLER 1
#define StdWidth 200L
#define StdHeight 60L
#define PAR 1
#define PRT 2
#define TOPBYTE 510
#define blockgroesse 500L
#define MemoryType 0L
#define upper(abfrage) (islower(abfrage) ? toupper(abfrage) : (abfrage))
char *stddatei="s:print.makros";
struct FileHandle *printer;
struct FileInfoBlock fileinfoblock;
struct IntuitionBase *IntuitionBase;
BYTE fehler=0,makrosgeladen=0;
long makfilesize;
int makrozahl;

struct IntuiText StandardIText={3,1,JAM2,5,3,NULL,NULL,NULL},
                 CANCEL,OK,RETRY,CONTINUE,
                 Body={2,1,JAM1,10,10,NULL,NULL,NULL},Body2;

char **makzeigeranfang=NULL,*makroanfang=NULL;


void Bearbeite();

char *pair(zeiger)
long zeiger;
{
  return (char *)(zeiger+=zeiger%2);
}

void IntuitionOeffnen()
{
  if(!(IntuitionBase=(struct IntuitionBase *)
       OpenLibrary("intuition.library",0L)))
  {
    fehler=FEHLER;
    Alert(AT_Recovery|AN_Intuition|AG_OpenLib,0L);
  }  
}

void ClosePrinter()
{
  if(printer)
  {
    Close(printer);
    printer=0L;
  }
}
void AllesSchliessen()
{
  if(makroanfang)
    FreeMem(makroanfang,makfilesize);
  if(makzeigeranfang)
    FreeMem(makzeigeranfang,(long)(makrozahl*sizeof(char *)));
  ClosePrinter();
  CloseLibrary(IntuitionBase);
}  

void schreib(string,laenge)
char *string;
long laenge;
{
  if(Write(printer,string,laenge)==-1L)
  {
    ClosePrinter();
    Body.IText=(UBYTE *)"Printer not ready";
    AutoRequest(NULL,&Body,&OK,&OK,0L,0L,StdWidth,StdHeight);
    fehler=FEHLER;
  }
}
    
unsigned int atoui(string)
register char **string;
{
  register int wert=0;
  
  while(**string>='0'&&**string<='9')
    wert=wert*10+*((*string)++)-'0';
  return wert;
}

void SuchAnfang(string)
register char **string;
{
  while(*((*string)++));
}

void SuchnAnfang(string,n)
char **string;
int n;
{
  int zaehler;
  for(zaehler=1;zaehler<=n;zaehler++)
    SuchAnfang(string);
}

void MachGross(string)
register char *string;
{
  while(*(string++)=upper(*string));
}

void OpenPrinter(kanal)
BYTE kanal;
{
  struct FileHandle *hilfszeiger;

  if(kanal==PAR)
    if(!(hilfszeiger=Open("PAR:",MODE_OLDFILE)))      /* Hier PAR: in SER: aendern */
    {
      Body.IText=(UBYTE *)"\"PAR:\" could not be opened"; /*Hier dasselbe aendern */
      AutoRequest(NULL,&Body,&OK,&OK,0L,0L,StdWidth+60,StdHeight);
      fehler=FEHLER;
      return;
    }
    else;
  else
    if(!(hilfszeiger=Open("PRT:",MODE_OLDFILE)))
    {
      Body.IText=(UBYTE *)"\"PRT:\" could not be opened";
      AutoRequest(NULL,&Body,&OK,&OK,0L,0L,StdWidth+60,StdHeight);
      fehler=FEHLER;
      return;
    }
  printer=hilfszeiger;
}

void Entschluessle(argzahl,argstring,file)
int *argzahl;
char **argstring;
FILE *file;
{
  int bytezaehler=0,wert;
  char *hilfsstring;
  
  *argzahl=0;
  if(!(*argstring=AllocMem((long)(TOPBYTE+2),MemoryType)))
  {
    Body.IText=(UBYTE *)"Not enough memory";
    AutoRequest(NULL,&Body,&OK,&OK,0L,0L,StdWidth,StdHeight);
    fehler=FEHLER;
    return;
  }
  hilfsstring=*argstring;
  wert=fgetc(file);
  while((bytezaehler<=TOPBYTE)&&(wert!=EOF)&&(wert!='\260')&&(wert!='\n'))
  {
    switch(wert)
    {
      case  ' ':
      case '\t':
      case '\f':
      case '\r':
        wert=fgetc(file);
        break;
         
      case '"':
        while((bytezaehler<=TOPBYTE)
             &&((wert=fgetc(file))!=EOF))
        {
          if(wert=='"')
            if((wert=fgetc(file))!='"')
              break;
          *(hilfsstring++)=wert;
          bytezaehler++;
        }
        *(hilfsstring++)='\0';
        bytezaehler++;
        (*argzahl)++;
        break;
         
      default:
        do
        {
          *(hilfsstring++)=wert;
          bytezaehler++;
        }
        while((bytezaehler<=TOPBYTE)
             &&((wert=fgetc(file))!=EOF)
             &&(wert!='\260')&&(wert!=' ')&&(wert!='\t')
             &&(wert!='\f')&&(wert!='\r')&&(wert!='\n'));
        *(hilfsstring++)='\0';
        bytezaehler++;
        (*argzahl)++;
    }
  }
}

void DruckFile(filename,druckerport)
char *filename;
BYTE druckerport;
{
  FILE *datei;
  char befehl[2],*vergleich="@\260",*argumente,requesterstring[TOPBYTE+2];
  int lesezeichen,argnum;
  BYTE anzbef=0,nochmal=1;

  strcpy(requesterstring,"\"\0");
  strcat(requesterstring,filename);
  strcat(requesterstring,"\"");
  Body.IText=(UBYTE *)requesterstring;
  Body2.IText=(UBYTE *)"cannot be opened...";
  
  while(!((datei=fopen(filename,"r"))||!nochmal))
    nochmal=AutoRequest(NULL,&Body2,&RETRY,&CANCEL,0L,0L,StdWidth,StdHeight+5);
  if(!nochmal)
  {
    fehler=FEHLER;
    return;
  }
  else  
  {
    while((lesezeichen=fgetc(datei))!=EOF)
      if((befehl[anzbef]=(char)lesezeichen)!=vergleich[anzbef])
      {
        schreib(befehl,(long)(anzbef+1));
        if(fehler)
        {
          fclose(datei);
          return;
        }
        anzbef=0;
      }
      else
        if(++anzbef==2)
        {
          Entschluessle(&argnum,&argumente,datei);
          if(fehler) return;
          ClosePrinter();
          Bearbeite(argnum,argumente);
          FreeMem(argumente,(long)(TOPBYTE+2));
          if(fehler) return;
          OpenPrinter(druckerport);
          if(fehler) return;
          anzbef=0;
        }
    fclose(datei);
  }
}

void druckzeichen(zeichen,zugriff)
char zeichen;
BYTE zugriff;
{
  if(!zugriff)OpenPrinter(PAR);
  if(fehler) return;
  schreib(&zeichen,1L);
  if(fehler) return;
  if(!zugriff)ClosePrinter();
}

void codereihe(codestring,wdh,zugriff)
char **codestring;
int wdh;
BYTE zugriff;
{
  char code,*hilf1,*hilf2;
  int zaehler;

  if(!zugriff) OpenPrinter(PAR);
  if(fehler) return;
  for(zaehler=1,hilf1=*codestring;zaehler<=wdh;zaehler++)
  {
    *codestring=hilf1;
    while(**codestring!='\0')
      if((**codestring>='0')&&(**codestring<='9'))
      {
        code=(BYTE)(atoui(codestring));
        schreib(&code,1L);
        if(fehler) return;
        while(**codestring&&(*((*codestring)++)!=','));
      }
      else
      {
        if((**codestring=='$')||(**codestring=='+'))
          (*codestring)++;
        hilf2=*codestring;
        while(**codestring&&(**codestring!=','))
          (*codestring)++;
        if(!zugriff)
        {
          ClosePrinter();
          OpenPrinter(PRT);
          if(fehler) return;
        }
        schreib(hilf2,(long)(*codestring-hilf2));
        if(fehler) return;
        if(!zugriff)
        {
          ClosePrinter();
          OpenPrinter(PAR);
          if(fehler) return;
        }
        *codestring+=(**codestring!='\0');
      }
  }  
  SuchAnfang(codestring);
  ClosePrinter();
}

void dateiladen()
{
  struct FileLock *lockzeiger;
  FILE *datei;
  int zeichen,zaehler,argzahl,laenge;
  char *makrostring,*hilfsstring,*makro,*hilfszeiger,**makrozeiger;
  long OkExam;
  
  makrozahl=0;
  if(lockzeiger=Lock(stddatei,SHARED_LOCK))
  {
    OkExam=Examine(lockzeiger,&fileinfoblock);
    UnLock(lockzeiger);
    if(OkExam)
    {
      if(makroanfang)
        FreeMem(makroanfang,makfilesize);
      if(makro=hilfszeiger=makroanfang=AllocMem(
         (makfilesize=(fileinfoblock.fib_Size<<1)+3),MemoryType))
      {
        if(datei=fopen(stddatei,"r"))
        {
          zeichen=fgetc(datei);
          while(zeichen!=EOF)
          {
            if(zeichen!=EOF&&zeichen!='\t'&&zeichen!='\f'&&zeichen!='\r'
               &&zeichen!='\n'&&zeichen!=' ')
            {
              makro=hilfszeiger;
              while(zeichen!=EOF&&zeichen!='\t'&&zeichen!='\f'&&zeichen!='\r'
                    &&zeichen!='\n'&&zeichen!=' ')
              {
                *(makro++)=(char)(upper(zeichen));
                zeichen=fgetc(datei);
              }
              *(makro++)='\0';
              if(zeichen==' '||zeichen=='\t')
              {
                while((zeichen=fgetc(datei))==' '||zeichen=='\t');
                if(zeichen!=EOF&&zeichen!='\f'&&zeichen!='\r'&&zeichen!='\n')
                {
                  fseek(datei,-1L,1);
                  Entschluessle(makro=pair(makro),&makrostring,datei);
                  if(fehler) return;
                  hilfsstring=makrostring;
                  argzahl=*((int *)makro);
                  makro+=sizeof(int);
                  for(zaehler=1;zaehler<=argzahl;zaehler++)
                  {
                    strcpy(makro,hilfsstring);
                    hilfsstring+=(laenge=strlen(hilfsstring)+1);
                    makro+=laenge;
                  }
                  FreeMem(makrostring,(long)(TOPBYTE+2));
                  makrozahl++;
                  makrosgeladen=1;
                  hilfszeiger=makro;
                }
              }
            }
            zeichen=fgetc(datei);
          }
          fclose(datei);
          if(makrozeiger=makzeigeranfang=(char **)AllocMem((long)
             (makrozahl*sizeof(char *)),MemoryType))
          {
            *makrozeiger=hilfszeiger=makroanfang;
            for(zaehler=2;zaehler<=makrozahl;zaehler++)
            {
              SuchAnfang(&hilfszeiger);
              hilfszeiger=pair(hilfszeiger);
              argzahl=*((int *)hilfszeiger);
              hilfszeiger+=sizeof(int);
              SuchnAnfang(&hilfszeiger,argzahl);
              *(++makrozeiger)=hilfszeiger;
            }
          }
          else
          {
            fehler=FEHLER;
            return;
          }
        }
      }
    }
  }
}

void printmakro(makrostring)
char *makrostring;
{
  int zaehler=0;
  char **makrozeiger,*makro;
  
  MachGross(makrostring);
  if(!makrosgeladen) 
  {
    dateiladen();
    if(!makrosgeladen||fehler)
    {
      Body.IText=(UBYTE *)stddatei;
      Body2.IText=(UBYTE *)"cannot be opened...";
      if(!AutoRequest(NULL,&Body2,&CONTINUE,&CANCEL,0L,0L,StdWidth,StdHeight+5))
      {
        fehler=FEHLER;
        return;
      }
      else return;
    }
  }
  makro=*(makrozeiger=makzeigeranfang);
  while(zaehler<makrozahl&&strcmp(makro,
        makrostring))
  {
    zaehler++;
    makro=*(++makrozeiger);
  }
  
  if(zaehler>=makrozahl)
  {
    Body.IText=(UBYTE *)makrostring;
    Body2.IText=(UBYTE *)"cannot be found...";
    if(!AutoRequest(NULL,&Body2,&CONTINUE,&CANCEL,0L,0L,StdWidth,StdHeight+5))
    {
      fehler=FEHLER;
      return;
    }
    
  }
  else
  {
    makro=pair(makro+strlen(makro)+1);
    Bearbeite(*((int *)makro),makro+sizeof(int));
    if(fehler) return;
  } 
}

void Bearbeite(anzahl,parameterstring)
int anzahl;
char *parameterstring;
{
  int argzaehler=0;
  unsigned int durchgaenge,whzaehler;
  BYTE zugriff;
  register char *hilfszeiger;
  
  while(++argzaehler<=anzahl)
  {
    zugriff=0;
    durchgaenge=1;
    switch(*parameterstring)
    {
      case '\0':
        parameterstring++;
        break;

      case '*':
        parameterstring++;
        durchgaenge=atoui(&parameterstring);
        if(!durchgaenge)
        {
          SuchAnfang(&parameterstring);
          break;
        }
      
      case '&':
        if(*parameterstring=='&')
        {
          parameterstring++;
          OpenPrinter(zugriff=PRT);
          if(fehler) return;
        }

      case '#':
        if(*parameterstring=='#')
        {
          parameterstring++;
          OpenPrinter(zugriff=PAR);
          if(fehler) return;
        }
      
      case  '\\':
      case '\33':
        if((*parameterstring=='\\')||(*parameterstring=='\33'))
        {  
          druckzeichen('\33',zugriff);
          if(fehler) return;
          parameterstring++;
          codereihe(&parameterstring,durchgaenge,zugriff);
          if(fehler) return;
          break;
        }

      case   '|':
      case '\34':
      case   '~':
        if((*parameterstring=='|')||(*parameterstring=='\34')||
           (*parameterstring=='~'))
        {  
          druckzeichen('\34',zugriff);
          if(fehler) return;
          parameterstring++;
          codereihe(&parameterstring,durchgaenge,zugriff);
          if(fehler) return;
          break;
        }

      case '%':
        if(*parameterstring=='%')
        {
          parameterstring++;
          codereihe(&parameterstring,durchgaenge,zugriff);
          if(fehler) return;
          break;
        }
      
      case '$':
      case '+':
        if((*parameterstring=='$')||(*parameterstring=='+'))
        {
          if(!zugriff)
          {
            OpenPrinter(PRT);
            if(fehler) return;
          }
          hilfszeiger=++parameterstring;
          while(*(parameterstring++));
          for(whzaehler=1;whzaehler<=durchgaenge;whzaehler++)
          {
            schreib(hilfszeiger,(long)(parameterstring-hilfszeiger-1));
            if(fehler) return;
          }
          ClosePrinter();
          break;
        }
      
      case '-':
        if(*parameterstring=='-')
        {
          parameterstring++;
          for(whzaehler=1;whzaehler<=durchgaenge;whzaehler++)
          {
            printmakro(parameterstring);
            if(fehler) return;
          }
          SuchAnfang(&parameterstring);
          break;
        }  

      case '@':
        if(*parameterstring=='@')
          parameterstring ++;

      default:  
        if(!zugriff)
        {
          OpenPrinter(zugriff=PRT);
          if(fehler) return;
        }
        for(whzaehler=1;whzaehler<=durchgaenge;whzaehler++)
        {
          DruckFile(parameterstring,zugriff);
          if(fehler) return;
        }
        ClosePrinter();
        SuchAnfang(&parameterstring);
        break;
    }
  }
}

main(argc,argv) 
int argc;
char **argv; 
{
  if(argc<2)
  {
    puts("\n  PRINT 1.3\n  (c) 5/90 Uli Bubenheimer\n");
    puts("  Usage: PRINT [*n][&|#][\\|\"|\"|%|$|-]string");
    puts("\n  n   : number of repetitions");
    puts("  &   : send data to printer port");
    puts("  #   : send data to parallel port");     /* Hier parallel in serial aendern */
    puts("  \\   : send \"ESCAPE\" (ESC) sequence to printer (ESC = decimal 27)");
    puts("  |,~ : send \"FORM SEPARATOR\" (FS) sequence to printer (FS = decimal 28)");
    puts("  %   : send decimal codes and text to printer");
    puts("  $,+ : send text to printer");
    puts("  -   : print macro");
    puts("  @ or no introduction character: print file\n");
    puts("  In file:   @\260 [*n][&|#][\\|\"|\"|%|$|-]string \260\n");
  }
  else
  {
    RETRY=OK=CANCEL=CONTINUE=StandardIText;
    CANCEL.IText=(UBYTE *)"Cancel";
    OK.IText=(UBYTE *)"OK";
    RETRY.IText=(UBYTE *)"Retry";
    CONTINUE.IText=(UBYTE *)"Continue";
    Body2=Body;
    Body2.NextText=&Body;
    Body2.LeftEdge=10;
    Body2.TopEdge=20;
    IntuitionOeffnen();
    if(!fehler)
      if((printer=Open("PRT:",MODE_OLDFILE))&&(Write(printer,"\0",1L)!=-1L))
      {
        ClosePrinter();
        Bearbeite(--argc,argv[1]);
        AllesSchliessen();
      } 
      else
      {
        Body.IText=(UBYTE *)"Printer not ready";
        AutoRequest(NULL,&Body,&OK,&OK,0L,0L,StdWidth,StdHeight);
        AllesSchliessen();
      }
  }    
}
