/****************************************************************************/
/*									    */
/* 	newhard.c							    */
/*									    */
/*	Ein Ersatz fuer hardcopy.c.					    */
/*	Druckt die Bitmap in 180dpi oder 360dpi auf einen NEC-P6	    */
/*	oder in 100dpi/300dpi auf einen HP-DESKJET.			    */
/*	Vorteil gegenueber hardcopy.c:					    */
/*		- schneller (30%-50%)					    */
/*		- besser kommentiert (zumindestens ich versteh's :-)	    */
/*									    */
/*						      	26.11.89 (hes)      */
/*									    */
/*	Erweiterung auf EPSON-FX und kompatible 9-Nadel-Drucker		    */
/*	mit 120x72dpi (DRAFT) oder 240x216dpi (HQ)			    */
/*									    */
/*						      	05.02.90 (kb)       */
/*									    */
/*	Einfuegen des Atari Laser Printer Treibers			    */
/*									    */
/*						      	28.03.90 (rbs)      */
/****************************************************************************/

#include "defines.h"

#include <stdio.h>

#ifdef ANSI
#  include <stdlib.h>
#  include <stddef.h>
#  include <string.h>
#endif

#include "globals.h"
#include "bitmap.h"

#ifdef ATARI
#  include <tos.h>
#  define Chk_Abort()		/* hope this works */
#endif

#ifdef AMIGA
# include <dos.h>
# include "amprint.i"
#endif

#include "newhard.i"
#include "globals.i"
#include "landscap.i"



/* extern vars */

extern int draft;			/* quality for hardcopy             */
extern int unidirect;			/* print-modi for hardcopy          */
extern int printer_type;		/* printer type for hardcopy        */
extern int landscape;			/* print in landscape modus	    */


/* lokale Funktionen */

/***** A T A R I  -  Funktionen ********************************************/
#ifdef ATARI
#include "ataridef.h"

static void check_key				Args((void));
static void prnout				Args((char c));
#endif

/***** HP - DeskJet Graphic-Befehle ****************************************/
static void print_int				Args((int n));
static void end_raster_graphics_hp		Args((void));
static void set_raster_graphics_res_hp		Args((int res));
static void set_raster_graphics_width_hp	Args((int width));
static void set_raster_graphics_mode_hp		Args((int mode));
static void start_raster_graphics		Args((void));
static void set_draft_print_hp			Args((void));
static void set_norm_print_hp			Args((void));
static void vert_pos_hp				Args((int blank_lines));
static void transfer_data_hp			Args((int nr));
static void set_temp_x_off_trans_data_hp	Args((int xoffset,
						      int number));
static void print_uni_bi_direct_hp		Args((int n));
static int  is_empty_line			Args((char *in_line_ptr,
						      int map_width));
static int  search_left_border			Args((char *in_line_ptr,
						      int map_width));
static int  search_right_border			Args((char *in_line_ptr,
						      int map_width));

/***** NEC - P6 Graphic-Befehle *******************************************/
static void print_180dpi_graphic_nec_p6		Args((int nr));
static void print_360dpi_graphic_nec_p6		Args((int nr));
static void print_clear_buffer_nec_p6		Args((char block[3][16]));
static void set_line_spacing180_nec_p6		Args((int sp));
static void set_line_spacing360_nec_p6		Args((int sp));

/***** EPSON-FX Graphic-Befehle *******************************************/
static void print_120dpi_graphic_epson_x	Args((int nr));
static void print_240dpi_graphic_epson_x	Args((int nr));
static void print_clear_buffer_epson_x		Args((char block[16]));
static void set_line_spacing_epson_x		Args((int sp));
static void move_head_by_epson_x		Args((int pos));
static void set_pica_norm_epson_x               Args((void));

/***** misc funktions ****************************************************/
static void print_uni_bi_direct_nadel		Args((int n));
static void move_head_to_nadel			Args((int pos));
static void line_feed				Args((void));
static int  skip_blank_words			Args((unsigned short *ptr,
						      int lines,
						      int offset,
						      int max));
static int  search_length_text			Args((unsigned short *ptr,
						      int lines,
						      int offset,
						      int max));

static void Hardcopy_hp				Args((struct bitmap *bmap,
						      long lineno,
						      int draft));
static void Hardcopy_hp_noo			Args((struct bitmap *bmap,
						      long lineno,
						      int draft));
static void Hardcopy_180dpi_nec_p6		Args((struct bitmap *bmap,
						      long lineno,
						      int draft));
static void Hardcopy_360dpi_nec_p6		Args((struct bitmap *bmap,
						      long lineno,
						      int draft));

static void Hardcopy_120dpi_epson_x		Args((struct bitmap *bmap,
						      long lineno));
static void Hardcopy_240dpi_epson_x		Args((struct bitmap *bmap,
						      long lineno));

#ifdef AZTEC_C		/* Version 5.0 */
#pragma regcall ( print_int(d0) )
#pragma regcall ( set_raster_graphics_res_hp(d0) )
#pragma regcall ( set_raster_graphics_width_hp(d0) )
#pragma regcall ( set_raster_graphics_mode_hp(d0) )
#pragma regcall ( vert_pos_hp(d0) )
#pragma regcall ( transfer_data_hp(d0) )
#pragma regcall ( set_temp_x_off_trans_data_hp(d0,d1) )
#pragma regcall ( print_uni_bi_direct_hp(d0) )
#pragma regcall ( /* d0 = */ search_left_border(a0,d0) )
#pragma regcall ( /* d0 = */ search_right_border(a0,d0) )
#pragma regcall ( Hardcopy_hp(a0,d0,d1) )
#pragma regcall ( print_180dpi_graphic_nec_p6(d0) )
#pragma regcall ( print_360dpi_graphic_nec_p6(d0) )
#pragma regcall ( print_clear_buffer_nec_p6(a0) )
#pragma regcall ( set_line_spacing180_nec_p6(d0) )
#pragma regcall ( set_line_spacing360_nec_p6(d0) )
#pragma regcall ( print_120dpi_graphic_epson_x(d0) )
#pragma regcall ( print_240dpi_graphic_epson_x(d0) )
#pragma regcall ( print_clear_buffer_epson_x(a0) )
#pragma regcall ( set_line_spacing_epson_x(d0) )
#pragma regcall ( print_uni_bi_direct_nadel(d0) )
#pragma regcall ( move_head_to_nadel(d0) )
#pragma regcall ( /* d0 = */ skip_blank_words(a0,d0,d1,d2) )
#pragma regcall ( /* d0 = */ search_length_text(a0,d0,d1,d2) )
#pragma regcall ( Hardcopy_180dpi_nec_p6(a0,d0) )
#pragma regcall ( Hardcopy_360dpi_nec_p6(a0,d0) )
#pragma regcall ( Hardcopy_120dpi_epson_x(a0,d0) )
#pragma regcall ( Hardcopy_240dpi_epson_x(a0,d0) )
#endif


/****** misc macros *******************************************************/
#define take_Bit(nr,lword)	(lword & (1<<nr))
#define FS			((char)(28))
#define ESC			((char)(27))
#ifndef LATTICE
#  define min(a,b)		(((a) < (b)) ? (a) : (b))
#endif




/***** A T A R I  -  Funktionen ********************************************/

#ifdef ATARI
long mymask = 0x08L;

static void check_key(void)
{
 if ((Kbshift(-1)&mymask)==0L)
   {  return; }
 Fatal(1,"Program aborted by user.",140);
}

static void prnout(c)
  register char c;
{
 while ((long)Bcostat(0)==0L)
  check_key();
 Bconout(0,0xff&c);
}


#ifdef TEST_IT
#  include <ctype.h>
  static void prnout(char c);

  static void prnout(c)
    char c;
  {
    if (isprint(c)) printf("%c",c);
  }
#endif	/* TEST_IT */


/***** Atari SLM 804 Ansteuerung *******************************************/

typedef struct
 {
  char *s_form;
  short s_xmin,
        s_ymin,
        s_nxln,
        b_width,
        b_height,
        d_xmin,
        d_ymin,
        scalefac;
 } SLM;

static void Hardcopy_SLM(struct bitmap *bmap, long lineno)
{
  FILE *fp;
  SLM o;

  fp=fopen("PRN:","w");

  o.s_form   =     (char *)bmap->pixptr;
  o.s_xmin   =     (short)0;
  o.s_ymin   =     (short)0;
  o.s_nxln   =     (short)(bmap->width/8);
  o.b_width  =     (short)bmap->width;
  o.b_height =     (short)bmap->height;
  o.d_xmin   =     (short)0;
  o.d_ymin   =     (short)0;
  o.scalefac =     (short)(draft+1);
/*
  o.scalefac =     (short)1;
*/

  check_key();
  fprintf(fp,"\033\022G%08lx \n\f",&o);
  fclose(fp);
}
#endif


/***** HP - DeskJet Graphic-Befehle ****************************************/

static void print_int(int n)
{
  char str[15];
  int i;

  sprintf(str,"%d",n);
  for (i=0; str[i] != '\0'; i++) {
    prnout((char)str[i]);
  }
}

static void print_uni_bi_direct_hp(int n)
{
  prnout((char)ESC);
  prnout((char)'&');
  prnout((char)'k');
  print_int(n);
  prnout((char)'W');
}

static void end_raster_graphics_hp(void)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'r');
  prnout((char)'B');
}

static void set_raster_graphics_res_hp(int res)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'t');
  print_int(res);
  prnout((char)'R');
}

static void set_raster_graphics_width_hp(int width)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'r');
  print_int(width);
  prnout((char)'S');
}

static void set_raster_graphics_mode_hp(int mode)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'b');
  print_int(mode);
  prnout((char)'M');
}

static void start_raster_graphics(void)		/* at leftmost position */
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'r');
  prnout((char)'0');
  prnout((char)'A');
}

static void set_temp_x_off_trans_data_hp(int xoffset, int number)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'b');
  print_int(xoffset);
  prnout((char)'x');
  print_int(number);
  prnout((char)'W');
}

static void vert_pos_hp(int blank_lines)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'p');
  prnout((char)'+');
  print_int(blank_lines);
  prnout((char)'Y');
}

static void set_draft_print_hp(void)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'r');
  prnout((char)'1');
  prnout((char)'Q');
}

static void set_norm_print_hp(void)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'r');
  prnout((char)'0');
  prnout((char)'Q');
}

static void transfer_data_hp(int nr)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)'b');
  print_int(nr);
  prnout((char)'W');
}

/*** ist die Zeile leer ***/
static int is_empty_line(char *in_line_ptr, int map_width)
{
  int i;

  for (i=0; i<map_width && *in_line_ptr == 0; i++, in_line_ptr++);

  return (i == map_width);
}

/*** suche erstes Byte != 0 von links ***/
static int search_left_border(char *in_line_ptr, int map_width)
{
  int i;
  
  for (i=0; i<map_width && *in_line_ptr == 0; i++, in_line_ptr++);

  return i;
}

/*** suche erstes Byte != 0 von rechts ***/
static int search_right_border(char *in_line_ptr, int map_width)
{
  int i;
  
  in_line_ptr += (long)((long)map_width-1L);
  for (i=map_width-1; *in_line_ptr == 0  && i>0; i--, in_line_ptr--);

  if (*in_line_ptr != 0) {
    i++;
  }

  return i;
}

static void Hardcopy_hp(struct bitmap *bmap, long lineno, int draft)
{
  char *in_line_ptr;
  int bytes, left_border, right_border;
  int lines, map_width, blank_lines, i;


  map_width = ((int)bmap->width) >> 3;		/* /8 in Bytes */

  end_raster_graphics_hp();
  if (draft == DRAFT_CHEAP || draft == HIGH_Q_CHEAP) {
    set_draft_print_hp();
  }
  if (draft == DRAFT || draft == DRAFT_CHEAP) {
    set_raster_graphics_res_hp(100);
  }
  else {
    set_raster_graphics_res_hp(300);
  }
  set_raster_graphics_width_hp((int)bmap->width);
  set_raster_graphics_mode_hp(0);		/* full graphics mode */
  start_raster_graphics();

  blank_lines = 0;			/* counter for the blank lines */

  for (lines=0; lines<(int)min(bmap->height,lineno); lines++) {
    in_line_ptr = ((char*)(bmap->pixptr))+(long)((long)lines*(long)map_width);
    left_border = search_left_border(in_line_ptr,map_width);
    if (left_border == map_width) {	/* the current line is totaly blank */
      blank_lines++;
    }
    else {				/* the current line isn't blank */
      if (blank_lines > 0) {
        /* skip the blank lines */
        if (blank_lines > 6) {
          /* grosse Luecke -> skip */
          end_raster_graphics_hp();
          if (draft == DRAFT || draft == DRAFT_CHEAP) {	/* 100dpi */
            vert_pos_hp(3*blank_lines);
          }
          else {			/* 300dpi */
            vert_pos_hp(blank_lines);
          }
          start_raster_graphics();
        }
        else {
          /* kleine Luecke -> Leerzeilen */
          for (i=0; i<blank_lines; i++) {
            transfer_data_hp(1);	/* skip line */
            prnout((char)0);
          }
        }
        blank_lines = 0;
      }
      right_border = search_right_border(in_line_ptr,map_width);
      if (left_border > 0) {
        /* skip blank left border */
        set_temp_x_off_trans_data_hp(left_border<<3,right_border-left_border);
        in_line_ptr += (long)left_border;
      }
      else {
        transfer_data_hp(right_border-left_border);
      }
#ifdef AMIGA
      if (bufferz + right_border-left_border < bufflen) {
        for (bytes=left_border; bytes<right_border; bytes++) {	/* bytes of line */
          buffer[bufferz++] = (char)*in_line_ptr++;
        } 			/* ^^ spart ein if statement pro byte ^^ */
      }
      else {
        for (bytes=left_border; bytes<right_border; bytes++) {	/* bytes of line */
          prnout((char)*in_line_ptr++);
        }
      }
#else
      for (bytes=left_border; bytes<right_border; bytes++) {	/* bytes of line */
        prnout((char)*in_line_ptr++);
      }
#endif
    }		/* else skip blank line */
    Chk_Abort();
  }		/* end for lines */
  end_raster_graphics_hp();
  if (blank_lines > 0) {	/* skip the rest of blank lines */
    /* skip the blank lines */
    if (draft == DRAFT || draft == DRAFT_CHEAP) {	/* 100dpi */
      vert_pos_hp(3*blank_lines);
    }
    else {			/* 300dpi */
      vert_pos_hp(blank_lines);
    }
  }
  if (draft == DRAFT_CHEAP || draft == HIGH_Q_CHEAP) {
    set_norm_print_hp();
  }
}


static void Hardcopy_hp_noo(struct bitmap *bmap, long lineno, int draft)
{
  char *in_line_ptr;
  int bytes;
  int lines, map_width, blank_lines, i;
  int right_border;

  /* use only PCL Level III features */

  map_width = ((int)bmap->width) >> 3;		/* /8 in Bytes */

  /* end_raster_graphics_hp(); */
  set_raster_graphics_mode_hp(0);		/* full graphics mode */
  start_raster_graphics();

  blank_lines = 0;			/* counter for the blank lines */

  for (lines=0; lines<(int)min(bmap->height,lineno); lines++) {
    in_line_ptr = ((char*)(bmap->pixptr))+(long)((long)lines*(long)map_width);
    if (is_empty_line(in_line_ptr,map_width)) {
      blank_lines++;
    }
    else {				/* the current line isn't blank */
      if (blank_lines > 0) {
        /* skip the blank lines */
        for (i=0; i<blank_lines; i++) {
          transfer_data_hp(1);	/* skip line */
          prnout((char)0);
        }
        blank_lines = 0;
      }
      right_border = search_right_border(in_line_ptr,map_width);
      transfer_data_hp(right_border);
#ifdef AMIGA
      if (bufferz + right_border < bufflen) {
        for (bytes=0; bytes<right_border; bytes++) {	/* bytes of line */
          buffer[bufferz++] = (char)*in_line_ptr++;
        } 			/* ^^ spart ein if statement pro byte ^^ */
      }
      else {
        for (bytes=0; bytes<right_border; bytes++) {	/* bytes of line */
          prnout((char)*in_line_ptr++);
        }
      }
#else
      for (bytes=0; bytes<right_border; bytes++) {		/* bytes of line */
        prnout((char)*in_line_ptr++);
      }
#endif
    }		/* else skip blank line */
    Chk_Abort();
  }		/* end for lines */
  end_raster_graphics_hp();

  if (blank_lines > 0) {	/* skip the rest of blank lines */
    /* skip the blank lines */
    for (i=0; i<blank_lines; i++) {
      transfer_data_hp(1);	/* skip line */
      prnout((char)0);
    }
  }
  if (draft == DRAFT_CHEAP || draft == HIGH_Q_CHEAP) {
    set_norm_print_hp();
  }
}


/***** NEC - P6 Graphic-Befehle *******************************************/

static void print_180dpi_graphic_nec_p6(int nr)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)39);
  prnout((char)(nr%256));
  prnout((char)(nr/256));
}

static void print_360dpi_graphic_nec_p6(int nr)
{
  prnout((char)FS);
  prnout((char)'Z');
  prnout((char)(nr%256));
  prnout((char)(nr/256));
}

/* Unerschied zw. 180/360 wg. Kompatiblitaet (ESC <-> FS) */
static void set_line_spacing180_nec_p6(int sp)
{
  prnout((char)ESC);
  prnout((char)'3');
  prnout((char)sp);
}

static void set_line_spacing360_nec_p6(int sp)
{
  prnout((char)FS);
  prnout((char)'3');
  prnout((char)sp);
}


/* sucht wortweise nach der ersten Spalte != 0 */
static int skip_blank_words(unsigned short *ptr, int lines, int offset, int max)
{
  int i,test, nr;
  unsigned short *p = ptr;

  nr = 0;
  do {
    i = 0;
    test = TRUE;
    while (test && i<lines) {
      test = (*p == 0);
      i++;
      p += offset;
    }
    if (test) {
      p = ++ptr;
      nr++;
    }
  } while (test && nr < max);
  return (nr);
}

/* sucht wortweise nach der ersten Spalte == 0 */
static int search_length_text(unsigned short *ptr, int lines, int offset, int max)
{
  int i,test, nr;
  unsigned short *p = ptr;

  nr = 0;
  do {
    i = 0;
    test = TRUE;
    while (test && i<lines) {
      test = (*p == 0);
      i++;
      p += offset;
    }
    if (!test) {
      p = ++ptr;
      nr++;
    }
  } while (!test && nr < max);
  return (nr);
}

/* gibt buffer aus und setzt ihn auf 0 */
static void print_clear_buffer_nec_p6(char block[3][16])
{
  register int j;

#ifdef AMIGA
  if (bufferz + 48 < bufflen) {
    for (j=15; j>=0; j--) {			/* print line */
      buffer[bufferz++] = (char)block[0][j];
      buffer[bufferz++] = (char)block[1][j];
      buffer[bufferz++] = (char)block[2][j];
    }
  }
  else {
    for (j=15; j>=0; j--) {			/* print line */
      prnout((char)block[0][j]);
      prnout((char)block[1][j]);
      prnout((char)block[2][j]);
    }
  }
  memset(&(block[0][0]),0,(size_t)(48));	/* clear print buffer (16*3=48) */
#else
  for (j=15; j>=0; j--) {			/* print line */
    prnout((char)block[0][j]);
    block[0][j] = (char)0;
    prnout((char)block[1][j]);
    block[1][j] = (char)0;
    prnout((char)block[2][j]);
    block[2][j] = (char)0;
  }
#endif
}


static void Hardcopy_180dpi_nec_p6(struct bitmap *bmap, long lineno, int draft)
{

  char block[3][16], *print, mask;
  unsigned short read_word, *ptr, *in_line_ptr;
  int map_width, lines, height;
  int rows, words, i, j, empty, full;

  map_width = ((int)bmap->width) >> 4;			/* /16 */


  /* 180dpi .......... */
  height = 24;

  memset(&(block[0][0]),0,(size_t)(16*3));		/* clear print buffer */
  set_line_spacing180_nec_p6(height);

  for (lines=0; lines<(int)min(bmap->height,lineno); lines+=height) {
    in_line_ptr = ((unsigned short*)(bmap->pixptr))+(long)((long)lines*(long)map_width);
    full = 0;
    for (words=0; words<map_width; words++) {	/* words of line */
      /* transform bitmap to printer-data */

      if (full == 0) {
        empty = skip_blank_words(in_line_ptr, height, map_width, map_width-words);
        words += empty;				/* skip blank words */
        in_line_ptr += (long)empty;

        if (words >= map_width) {
          continue;	/* same as break */
        }
        if (empty > 0) {
          int skip = words*16;
          int rest = skip % 3;
  
          move_head_to_nadel(skip/3);		/* skip spaces */
          print_180dpi_graphic_nec_p6(rest);	/* skip rest */
          for (i=0; i<rest*3; i++) {
            prnout((char)0);
          }
        }
      }

      if (full == 0) {
	full = search_length_text(in_line_ptr, height, map_width, map_width-words);
	if (full > 0) {
	  print_180dpi_graphic_nec_p6(full*16);	/* init printer */
	}
      }

      ptr = in_line_ptr++;
      for (rows=0; rows<3; rows++) {
        print = &(block[rows][0]);
        for (j=0; j<8; j++) {
          read_word = *ptr;
          ptr += map_width;			/* set ptr to next row */
          mask = 1 << ( 7-j);			/* test mask */
          for (i=0; i<16; i++) {		/* transf. a long word */
            if (take_Bit(i,read_word) != 0) {
	      print[i] |= mask;
	    }
          }
        }
      }
      if (full == 0) {
        print_180dpi_graphic_nec_p6(16);	/* init printer */
      }
      else {
        full--;
      }
      print_clear_buffer_nec_p6(block);
      Chk_Abort();
    }
    /* end of line */
    line_feed();
  }
}

static void Hardcopy_360dpi_nec_p6(struct bitmap *bmap, long lineno, int draft)
{
  char block[3][16], *print, mask;
  unsigned short read_word, *ptr, *in_line_ptr;
  int map_width, lines, height;
  int rows, words, i, j, empty, full, pass;
  long offset;

  map_width = ((int)bmap->width) >> 4;			/* /16 */


  /* 360dpi .......... */
  height = 48;

  memset(&(block[0][0]),0,(size_t)(16*3));		/* clear print buffer */

  for (lines=0; lines<(int)(min(bmap->height,lineno)); lines+=height) {
    offset = (long)lines*(long)map_width;
    for (pass=0; pass<2; pass++) {
      in_line_ptr = ((unsigned short*)(bmap->pixptr))+offset;
      if (pass == 0) {
        set_line_spacing360_nec_p6(1);	/* fuer Pass 2 */
      }
      else {
        set_line_spacing360_nec_p6(47);
        in_line_ptr += (long)map_width;	/* ungerade Adressen */
      }
      full = 0;
      for (words=0; words<map_width; words++) {	/* words of line */
        /* transform bitmap to printer-data */
  
        if (full == 0) {
          empty = skip_blank_words(in_line_ptr, height, map_width, map_width-words);
          words += empty;				/* skip blank words */
          in_line_ptr += (long)empty;
  
          if (words >= map_width) {
            if (empty == map_width && pass == 0) {
              pass = 1;		/* ganze Zeile leer => skip sie auf einmal */
              set_line_spacing360_nec_p6(48);
#ifdef DEBUG
	      if (DeBug) {
	        printf("Skip line.\n");
	      }
#endif
            }
            continue;	/* same as break */
          }
          if (empty > 0) {
            int skip = words*16;
            int rest = skip % 6;
    
            move_head_to_nadel(skip/6);			/* skip spaces */
            print_360dpi_graphic_nec_p6(rest);		/* skip rest */
            for (i=0; i<rest*3; i++) {
              prnout((char)0);
            }
          }
        }
  
        if (full == 0) {
  	  full = search_length_text(in_line_ptr, height, map_width, map_width-words);
  	  if (full > 0) {
	    print_360dpi_graphic_nec_p6(full*16);	/* init printer */
	  }
        }

        ptr = in_line_ptr++;
        for (rows=0; rows<3; rows++) {
          print = &(block[rows][0]);
          for (j=0; j<8; j++) {
            read_word = *ptr;
            ptr += 2*map_width;			/* 2* wg. 2 passes */
            mask = 1 << (7-j);			/* test mask */
            for (i=0; i<16; i++) {		/* transf. a long word */
              if (take_Bit(i,read_word) != 0) {
	        print[i] |= mask;
	      }
            }
          }
        }
        if (full == 0) {
          print_360dpi_graphic_nec_p6(16);	/* init printer */
        }
        else {
          full--;
        }
        print_clear_buffer_nec_p6(block);
        Chk_Abort();
      }
      /* end of line */
      line_feed();
    }	/* pass */
  }
}

/***** EPSON-FX Graphic-Befehle *******************************************/

static void print_120dpi_graphic_epson_x(int nr)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)1);
  prnout((char)(nr%256));
  prnout((char)(nr/256));
}

static void print_240dpi_graphic_epson_x(int nr)
{
  prnout((char)ESC);
  prnout((char)'*');
  prnout((char)3);
  prnout((char)(nr%256));
  prnout((char)(nr/256));
}


static void set_pica_norm_epson_x()
{
  prnout((char)ESC);   /* masterprintmode */
  prnout((char)'!');   /* set pitch to pica, 10cpi, nonboldface, nonitalic */
  prnout((char)0);     /* nonunderline and nondoublestrike */
  prnout((char)13);
}


static void move_head_by_epson_x(int pos)
{
  int num;

  for(num=0; num<pos; num++) { /* print spaces */
    prnout((char)(32));
  }

#ifdef UROLD
  prnout(ESC);				/* set graphic mode to 60dpi */
  prnout('K');

  prnout((unsigned char)(pos%256));
  prnout((unsigned char)(pos/256));
  for(num=0; num<pos; num++) {
    prnout((char)(0));
  }
#endif
}


static void set_line_spacing_epson_x(int sp)
{
  prnout((char)ESC);
  prnout((char)'3');
  prnout((char)sp);
}


/* gibt buffer aus und setzt ihn auf 0 */
static void print_clear_buffer_epson_x(char *block)
{
  register int j;

  for (j=15; j>=0; j--) {			/* print line */
    prnout((char)block[j]);
    block[j] = (char)0;
  }
}


static void Hardcopy_120dpi_epson_x(struct bitmap *bmap, long lineno)
{

  char block[16], *print, mask;
  unsigned short read_word, *ptr, *in_line_ptr;
  int map_width, lines, height;
  int words, i, j, empty, full;

  map_width = ((int)bmap->width) >> 4;			/* /16 */


  /* 120dpi .......... */
  height = 8;

  memset(&(block[0]),0,(size_t)16);		/* clear print buffer */
  set_line_spacing_epson_x(height*3);

  for (lines=0; lines<(int)min(bmap->height,lineno); lines+=height) {
    in_line_ptr = ((unsigned short*)(bmap->pixptr))+(long)((long)lines*(long)map_width);
    full = 0;
    for (words=0; words<map_width; words++) {	/* words of line */
      /* transform bitmap to printer-data */

      if (full == 0) {
        empty = skip_blank_words(in_line_ptr, height, map_width, map_width-words);
        words += empty;				/* skip blank words */
        in_line_ptr += (long)empty;

        if (words >= map_width) {
          continue;	/* same as break */
        }
        if (empty > 0) {
	  if (printer_type == EPSON_X_NOO) {	/* no optim */
	    int skip, rest;

            if(words > 0) {     /* start of line ?  */
              skip = empty*16; /* optimize */
              rest = skip %12;
              move_head_by_epson_x(skip/12);		/* skip spaces */
            }
            else {
              rest = empty*16;
            }
            if (rest > 0) {
              print_120dpi_graphic_epson_x(rest);		/* skip rest */
              for (i=0; i<rest; i++) {
                prnout((char)0);
              }
            }
          }
          else {
            move_head_to_nadel(words*8);		/* skip spaces */
          }
        }

        if (printer_type == EPSON_X_NOO) {
          full = map_width - words;	/* kein optimieren innerhalb der Zeile */
        }
        else {
	  full = search_length_text(in_line_ptr, height, map_width, map_width-words);
	}
	if (full > 0) {
	  print_120dpi_graphic_epson_x(full*16);	/* init printer for 16*full bytes*/
	}
      }

      ptr = in_line_ptr++;
      print = &(block[0]);
      for (j=0; j<8; j++) {
        read_word = *ptr;
        ptr += map_width;			/* set ptr to next row */
        mask = 1 << ( 7-j);			/* test mask */
        for (i=0; i<16; i++) {			/* transf. a long word */
          if (take_Bit(i,read_word) != 0) {
	     print[i] |= mask;
	  }
        }
      }

      if (full == 0) {
        print_120dpi_graphic_epson_x(16);	/* init printer */
      }
      else {
        full--;
      }
      print_clear_buffer_epson_x(block);
      Chk_Abort();
    }
    /* end of line */
    line_feed();
  }
}

static void Hardcopy_240dpi_epson_x(struct bitmap *bmap, long lineno)
{
  char block[16], *print, mask;
  unsigned short read_word, *ptr, *in_line_ptr;
  int map_width, lines, height;
  int words, i, j, empty, full, pass;
  long offset;
#ifdef TTESTT
  char *line_buffer;
  int line_ptr;
#endif

  map_width = ((int)bmap->width) >> 4;			/* /16 */

#ifdef TTESTT
  if ((line_buffer = malloc(map_width * 2)) == NULL) {
    Fatal(10,"no memory!", 141);
  }
  line_ptr = 0;
#endif


  /* 240dpi .......... */
  height = 24;

  memset(&(block[0]),0,(size_t)16);			/* clear print buffer */

  for (lines=0; lines<(int)min(bmap->height,lineno); lines+=height) {
    offset = (long)lines*(long)map_width;
    for (pass=0; pass<3; pass++) {
      in_line_ptr = ((unsigned short*)(bmap->pixptr))+offset+(long)((long)map_width*(long)pass);
      if (pass < 2) {
        set_line_spacing_epson_x(1);		/* fuer Passes 2 & 3 */
      }
      else {
        set_line_spacing_epson_x(22);
      }
      full = 0;
      for (words=0; words<map_width; words++) {	/* words of line */
        /* transform bitmap to printer-data */

        if (full == 0) {
          empty = skip_blank_words(in_line_ptr, height, map_width, map_width-words);
          words += empty;				/* skip blank words */
          in_line_ptr += (long)empty;

          if (words >= map_width) {
            if (empty == map_width && pass <= 1) {
              pass = 2;		/* ganze Zeile leer => skip sie auf einmal */
              set_line_spacing_epson_x(24);
#ifdef DEBUG
	      if (DeBug) {
	        printf("Skip line.\n");
	      }
#endif
            }
            continue;	/* same as break */
          }
          if (empty > 0) {
	    if (printer_type == EPSON_X_NOO) {		/* no optim */
	      int skip, rest;

              if(words > 0) {     /* start of line ?  */
                skip = empty*16; /* optimize */
                rest = skip %24;
                move_head_by_epson_x(skip/24);		/* skip spaces */
              }
              else {
                rest = empty*16;
              }
              if (rest > 0) {
                print_240dpi_graphic_epson_x(rest);		/* skip rest */
                for (i=0; i<rest; i++) {
                  prnout((char)0);
                }
              }
            }
            else {
              move_head_to_nadel(words*4);		/* skip spaces */
            }
          }

          if (printer_type == EPSON_X_NOO) {
            full = map_width - words;	/* kein optimieren innerhalb der Zeile */
          }
          else {
    	    full = search_length_text(in_line_ptr, height, map_width, map_width-words);
    	  }
  	  if (full > 0) {
	    print_240dpi_graphic_epson_x(full*16);	/* init printer */
	  }
        }

        ptr = in_line_ptr++;
        print = &(block[0]);
        for (j=0; j<8; j++) {
          read_word = *ptr;
          ptr += 3*map_width;			/* 3* wg. 3 passes */
          mask = 1 << (7-j);			/* test mask */
          for (i=0; i<16; i++) {		/* transf. a long word */
            if (take_Bit(i,read_word) != 0) {
	       print[i] |= mask;
	    }
          }
        }

        if (full == 0) {
          print_240dpi_graphic_epson_x(16);	/* init printer */
        }
        else {
          full--;
        }
        print_clear_buffer_epson_x(block);
        Chk_Abort();
      }
      /* end of line */
      line_feed();
    }	/* pass */
  }
}

static void print_uni_bi_direct_nadel(int n)
{
  if (n == UNIDIR) {
    prnout((char)ESC);
    prnout((char)'U');
    prnout((char)(1));
  }
  else {
    prnout((char)ESC);
    prnout((char)'U');
    prnout((char)(0));
  }
}

static void move_head_to_nadel(int pos)
{
  prnout((char)ESC);
  prnout((char)'$');
  prnout((char)(pos%256));
  prnout((char)(pos/256));
}


static void line_feed(void)
{
  /*  prnout((char)13); */
  prnout((char)10);
}


/*************************************************************************/
/** Schnittstelle nach aussen:						**/

void FormFeed(void)
{
 if (printer_type != SLM804)
  {
   prnout((char)12);
  }
}


void Hardcopy(struct bitmap *bmap, long lineno)
{
  switch (printer_type)
   {
    case NEC_P6:
      print_uni_bi_direct_nadel(unidirect);

      if (draft == HIGH_Q) {
        if (landscape) {
          Querdruck(bmap, NEC_P6_HIGH_Q_PWIDTH, draft, Hardcopy_360dpi_nec_p6);
        }
        else {
          Hardcopy_360dpi_nec_p6(bmap,lineno,draft);
        }
      }
      else {
        if (landscape) {
          Querdruck(bmap, NEC_P6_DRAFT_PWIDTH, draft, Hardcopy_180dpi_nec_p6);
	}
        else {
          Hardcopy_180dpi_nec_p6(bmap,lineno,draft);
	}
      }
      break;

    case DESKJET:
      if (unidirect == BIDIR) {
        print_uni_bi_direct_hp(0);
      }
      if (landscape) {
        Querdruck(bmap, DESKJET_DRAFT_PWIDTH, draft, Hardcopy_hp);
      }
      else {
        Hardcopy_hp(bmap,lineno,draft);
      }
      break;

    case DESKJET_NOO:
      if (unidirect == BIDIR) {
        print_uni_bi_direct_hp(0);
      }
      if (landscape) {
        Querdruck(bmap, DESKJET_DRAFT_PWIDTH, draft, Hardcopy_hp_noo);
      }
      else {
        Hardcopy_hp_noo(bmap,lineno,draft);
      }
      break;

   case SLM804:
#     ifdef ATARI
      Hardcopy_SLM(bmap, lineno);
      if (landscape) {
        Warning("Can't print in landscape modus!");
      }
      else {
        Hardcopy_SLM(bmap,lineno,draft);
      }
#     endif
      break;

   case EPSON_X:
   case EPSON_X_NOO:
   default:
      print_uni_bi_direct_nadel(unidirect);
      if (draft == HIGH_Q) {
        if (landscape) {
          Warning("Can't print in landscape modus!");
	}
        else {
          Hardcopy_240dpi_epson_x(bmap,lineno);
        }
      }
      else {
        if (landscape) {
          Warning("Can't print in landscape modus!");
	}
        else {
          Hardcopy_120dpi_epson_x(bmap,lineno);
        }
      }
        
      break;
   }
}
