char *Cr="PrintFx 2.7  09-MAY-89 by D.W.Reisig, NL 1151AV10\n";
char *WTTl=" PrintFx 2.7 ";

/*

This code is a good example how NOT to write a program. Then why
did I include the source?
This is a utility that I made when I had the Amiga one month or so.
And I could not get my files to my printer without printing over
the perforation, or it stopped halfway the sheet when the printing
was done. Annyway I got irritated.
I have an Epson FX80+. I thought that made this program useless
for other printers. Suddenly the hole world can use it on their
printers as well. This is why I included the source. Perhaps it
does not work on your printer. Now you can change it (if you can
decipher the code).
I used Lattice 5.02 and Asm 5.02 as compilers but 4.00 does it also
fine.

*/


#include <libraries/dos.h>
#include <setjmp.h>>
#include <exec/types.h>
#include <intuition/intuition.h>

#define CMDNAMES 1	/* one inputfile 				*/
#define ISM 64		/* init string max				*/
#define IOBUFFER 512	/* twice allocated from the stack		*/
#define RMARGINIT 255	/* means: not used				*/
#define UNIT_INCH 216	/* there are 216 1/3 units in a inch		*/
#define EOF -1		/*						*/
#define ESC 0x1b	/*						*/
#define SKIPOVERA 198	/* skip-over space in 1/3 dots if back shift	*/
#define SKIPOVERB 264   /* skip-over space if not shifted back		*/
#define PERFSHIFT 54	/* paper shift back at start in 1/3 dots	*/
#define ERROR -1	/* Used with longjump in an error situation	*/
#define	STOP 1		/* Used with longjump in a non error situation	*/

jmp_buf Mains;		/* easy does it					*/
char DeinitPaper[]={ ESC,'J',PERFSHIFT,ESC,'C',0,0 } ;
#define DEINITLEN 7	/* size of DeinitPaper[]			*/
char *Path[CMDNAMES+1];
char *Title=NULL;	/* title available				*/
int  Infile;		/* DOS file handler				*/
int  Prt;		/* DOS file handler				*/
int  Page=0;		/* printer determines pagelength		*/
int  Lmarg=5;		/* left margin					*/
int  Rmarg=RMARGINIT;	/* right margin not given			*/
int  Cpline;		/* will contain number of possible chars/line	*/
int  Mode=64;		/* 64=unused					*/
int  Lsp=29;		/* Linespace .13456" 3.41mm 82 l/p		*/
int  Type=1;		/* type is elite				*/
int  Plen=11;		/* paper length	in inches			*/
int  SpPTab=8;		/* Spaces per Tab (make an option of it iyl	*/
char *Pr;		/* Name of this utility from cmdline		*/
char Cond=0;		/* not condensed				*/
char Empha=0;		/* not emphasized				*/
char Double=0;		/* not double strike				*/
char Prop=0;		/* not proportional				*/
char Super=0;		/* super script is off				*/
char Trunc=1;		/* truncation line overflow			*/
char PlBack=1;		/* paper is pulled back at start		*/
char EndDet=1;		/* paper end detection on			*/
char OutStd=0;		/* Output not standard; PAR:			*/
char Let='\f';		/* last character send to printer, if it is FF,	*/
			/* no extra FF must be sent, and no FF if	*/
			/* nothing has been printed			*/
char Er=1;		/* stderr may be used				*/

void ps(),ErrMsg(),Explain();
char gc();
extern int ConOut;


main(argc,argv)
register int argc;
register char *argv[];
{
  register int argcnt, namecnt, ret, err=0;

  Pr=argv[0];  /* adapt name the user uses */
  if (argc>1){
    if (*argv[1]=='?'){
      Explain();
      return(0);
    }
  }
  for (argcnt=1,namecnt=0;argcnt<argc;++argcnt) if (*(argv[argcnt])!='-'){
    Path[namecnt++]=argv[argcnt];
    if (namecnt>CMDNAMES) break;
  }
  procopts(argc,argv);
  if (namecnt>CMDNAMES){
    ErrMsg("Donot know what to do with: ",Path[CMDNAMES]);
    return(0);
  }
  if (calc()) return(0); /* some things must be calculated */

  if (Path[0]){
    if ((Infile=Open(Path[0],MODE_OLDFILE))==0){
      ErrMsg("Cannot open: ",Path[0]);
      return(0);
    }
  } else Infile=Input();
  if (!OutStd){
    if ((Prt=Open("PAR:",MODE_OLDFILE))==0){
      ErrMsg("No printer (PAR:)","");
      goto CleanUp;
    }
  } else Prt=Output();
  ret=setjmp(Mains);    /* return point from deep level errors */
  if (ret) goto CleanUp;
  MakeOffSwitch(WTTl);  /* nice to stop when you did RUN pr.. */

  initprinter();
  filetoprinter();
  deinitprinter();
  goto CleanUp1;

CleanUp:
  if (ret==ERROR)  err=IoErr();

CleanUp1:
  RemOffSwitch();
  if (!OutStd)  Close(Prt);
  if (Path[0])  Close(Infile);
  return(err);
}   /* main */


procopts(argc,argv)
register int argc;
register char *argv[];
{
  register int argcnt;
  register char *option, *error, avail;
  int temp;
  for (argcnt=1;argcnt<argc;++argcnt){
    if (*(option=argv[argcnt])=='-'){
      avail=1;
      while (avail) switch(*(error=option++)){

case '-'  : break;
case '\0' : avail=0; break;
case '?'  : if (*option=='?') ConMsg(Cr); else Explain();  XCEXIT(0);
case 't'  : Title  =(*option=='=')?option+1:option; avail=0; break;
case 'i'  : option+=stoi(option,&Plen);   break;
case 'l'  : option+=stoi(option,&Lmarg);  break;
case 'r'  : option+=stoi(option,&Rmarg);  break;
case 'p'  : option+=stoi(option,&temp);
            if (temp==0) Type&=0xfe;
            else Page=temp;
            break;
case 'm'  : option+=stoi(option,&Mode);   break;
case 'n'  : option+=stoi(option,&Lsp);    break;
case 'c'  : Type|=0x04;  break;
case 'e'  : switch(*(option++)){
              case 'd' : EndDet=0;    break;
              case 'l' : Type|=0x01;  break;
              case 'm' : Type|=0x08;  break;
              case 'n' : Type|=0x20;  break;
              default  : goto opterr;
            }
case 'd'  : Type|=0x10;  break;
case 'v'  : Prop=1;      break;
case 'x'  : Trunc=0;     break;
case 'y'  : PlBack=0;     break;
case 'o'  : OutStd=1;    break;
case 's'  : Er=0;	 break;
case 'q'  : Super=1;     break;
default   : goto opterr;

  } } } return(0);
opterr:
  Explain();
  ErrMsg("Unknown option: -",error);
  XCEXIT(0);
}   /* procopts */


calc()
{
  register int choose, avail;
  register unsigned char *data;
  if (Mode==64)   Mode=Type;
  data="\x50\x60\x28\x30\x89\xA0\x44\x50";
  choose=(int)Mode&0x05;	/* b0 on is elite, b2 on is condensed */
  if (Mode&0x20) choose+=0x02;	/* b1 on is enlarged */ 
  Cpline=(int)*(data+choose);
  if (Rmarg!=RMARGINIT){
    if (Rmarg>Cpline){
      ErrMsg("Right margin too large","");
      return(-1);
    }
  } else Rmarg=Cpline;
  Cpline=Rmarg-Lmarg;
  avail=((Plen*UNIT_INCH)-((PlBack)?SKIPOVERA:SKIPOVERB))/Lsp;
  if (Page){
    if (Page>avail){
      ErrMsg("You ask too much lines per page","");
      return(-1);
    }
  } else Page=avail;
  return(0);
}


initprinter()
{
  char initstring[ISM];
  register char *is=initstring;
  register int len;

  if (PlBack){
    *(is++)=ESC;   *(is++)='j';   *(is++)=PERFSHIFT;
  }
  *(is++)=ESC;   *(is++)='@';
  *(is++)=ESC;   *(is++)='C';   *(is++)=0;     *(is++)=Plen;
  *(is++)=ESC;   *(is++)='!';   *(is++)=Mode;
  if (Prop)    { *(is++)=ESC;   *(is++)='p';   *(is++)='1';    }
  *(is++)=ESC;   *(is++)=EndDet?'9':'8';  
  *(is++)=ESC;   *(is++)='3';   *(is++)=Lsp;
  if (Lmarg)   { *(is++)=ESC;   *(is++)='l';   *(is++)=Lmarg;  }
  *(is++)=ESC;   *(is++)='Q';   *(is++)=Rmarg;
  if (Super)   { *(is++)=ESC;   *(is++)='S';   *(is++)='0';    }
  
  len=is-initstring;
  if (Write(Prt,initstring,len)!=len) longjmp(Mains,ERROR);
  return(0);
}


deinitprinter()
{
  if (Let!='\f') if (Write(Prt,"\f",1)!=1) longjmp(Mains,ERROR);
  if (PlBack){
    DeinitPaper[DEINITLEN-1]=Plen;  /* FF button works ok now */
    if (Write(Prt,DeinitPaper,DEINITLEN)!=DEINITLEN) longjmp(Mains,ERROR);
  }
  return(0);
}



char *Inb, *Outb;  /* two buffer pointer global from here on */


filetoprinter()
{
  char inbuffer[IOBUFFER], outbuffer[IOBUFFER];  /* from the stack */
  register int line, i;
  register char c;
  
  Inb=inbuffer; Outb=outbuffer;

  i=Lmarg;  
  line=newpage();
  while (1){
    c=gc();
check:
    if (c=='\t') i+=(SpPTab-((i-Lmarg)%SpPTab));  /* expand tabs */
    else ++i;
    if (c=='\n'){                   /* newline */
      i=Lmarg;
      line=newline(line);
    } else if (c=='\f'){            /* formfeed, newline inherent */
      i=Lmarg;
      line=newpage(line);
    } else if (i>Rmarg){            /* R-marge reached: newline */
      i=Lmarg;
      line=newline(line);
      if (Trunc) trunc();           /* skip rest of line  */
      else goto check;              /* no, print rest on next line */
    } else pc(c);
    if (c==EOF) break;
  }
  return(0);  
}


newline(line)
register int line;
{
  ++line;
  if (line>=Page)  line=newpage();
  else  pc('\n');
  return(line);
}


trunc()
{
  char t;
  while ((t=gc())>=0) if (t=='\n') break;
  return(0);
}


newpage()
{
  static pagenr=0;
  register out, factor, tpagenr, nr;
  char ptd;
  if ((pagenr)&&(Let!='\f')) ps("\r\f");
  ++pagenr;
  if (Title){
    out=0;
    ps("page "); out+=5;
    for (tpagenr=pagenr,factor=1000,ptd=0;factor;factor/=10){
      if (nr=(tpagenr/factor)) ptd=1;
      if (ptd){
        pc(nr+0x30);
        ++out;
	tpagenr-=(nr*factor);
      }
    }
    for (;out<10;++out) pc(' ');
    ps(Title); out+=strlen(Title);
    factor=Cpline-strlen(Path[0])-Lmarg;
    while (out++<factor) pc(' ');
    ps(Path[0]);
    ps("\n\n");
    return(2); /* now two lines used */
  }
  return(0); /* no title; no lines used */
}
	
  

char gc()  /* return a char, if buffer empty ask dos for more */
{
  static avail=0, pos=0;
  
  if (avail==0){
    if ((avail=Read(Infile,Inb,IOBUFFER))<1){
      if (avail<0) longjmp(Mains,ERROR);
      return(EOF);
    }
    pos=0;
  }
  --avail;
  return(*(Inb+pos++));
} /* gc */


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


pc(c)  /* store a char, if buffer full, flush it */
char c;
{
  static pos=0;

  if (c!=EOF){
    Let=*(Outb+pos++)=c;
    if (pos<IOBUFFER) return(0);
  }
  if ((TestOffSwitch())||(SetSignal(0,0x3000)&0x3000)){
    deinitprinter();
    longjmp(Mains,STOP);
  }
  if (Write(Prt,Outb,pos)!=pos) longjmp(Mains,ERROR);
  pos=0;
  return(0);
} /* pc */

