/* scs.c -- Converts scs to forms useable by scs2ascii, scs2ps, and scs2pdf.
 * Copyright (C) 2000 Michael Madore
 *
 * This file is part of TN5250.
 *
 * TN5250 is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
 * (at your option) any later version.
 *
 * TN5250 is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include "tn5250-private.h"

/*
#define DEBUG
#define VERBOSE
*/


/* Device control */
void scs_sic (Tn5250SCS * This);
void scs_sea (Tn5250SCS * This);
void scs_noop (Tn5250SCS * This);
void scs_transparent (Tn5250SCS * This);
void scs_spsu (Tn5250SCS * This);

/* Page control */
void scs_ppm (Tn5250SCS * This);
void scs_spps (Tn5250SCS * This);
void scs_shf (Tn5250SCS * This);
void scs_svf (Tn5250SCS * This);
void scs_ff (Tn5250SCS * This);
void scs_rff (Tn5250SCS * This);
void scs_sto (Tn5250SCS * This);
void scs_shm (Tn5250SCS * This);
void scs_svm (Tn5250SCS * This);
void scs_sffc (Tn5250SCS * This);

/* Font controls */
void scs_scgl (Tn5250SCS * This);
void scs_scg (Tn5250SCS * This);
void scs_sfg (Tn5250SCS * This);
void scs_scd (int *cpi);

/* Cursor control */
void scs_pp (Tn5250SCS * This);
void scs_rdpp (Tn5250SCS * This);
void scs_ahpp (Tn5250SCS * This);
void scs_avpp (Tn5250SCS * This);
void scs_rrpp (Tn5250SCS * This);
void scs_sbs (Tn5250SCS * This);
void scs_sps (Tn5250SCS * This);
void scs_nl (Tn5250SCS * This);
void scs_irs (Tn5250SCS * This);
void scs_rnl (Tn5250SCS * This);
void scs_irt (Tn5250SCS * This);
void scs_stab (Tn5250SCS * This);
void scs_ht (Tn5250SCS * This);
void scs_it (Tn5250SCS * This);
void scs_sil (Tn5250SCS * This);
void scs_lf (Tn5250SCS * This);
void scs_cr (Tn5250SCS * This);
void scs_ssld (Tn5250SCS * This);
void scs_sls (Tn5250SCS * This);

/* Generation controls */
void scs_sgea (Tn5250SCS * This);

void scs_process2b (Tn5250SCS * This);
void scs_processd2 (Tn5250SCS * This);
void scs_process03 (unsigned char nextchar, unsigned char curchar);
void scs_scs (int *cpi);
void scs_process04 (unsigned char nextchar, unsigned char curchar, int *cpi);
void scs_processd1 ();
void scs_process06 ();
void scs_process07 ();
void scs_processd103 ();
void scs_jtf (unsigned char curchar);
void scs_sjm (unsigned char curchar);
void scs_processd3 (Tn5250SCS * This);
void scs_main (Tn5250SCS * This);
void scs_init (Tn5250SCS * This);
void scs_default (Tn5250SCS * This);


/* Set Initial Conditions (SIC).  This is part of Device Control.  SIC
 * has a one byte parameter that follows it with the following meanings:
 * 1 - word processing initialization
 * 255 - data processing initialization (default)
 * all others - invalid
 *
 * According to the manual, this control is ignored by all printers.
 */
void
scs_sic (Tn5250SCS * This)
{
  unsigned char curchar;

  curchar = fgetc (stdin);

  if (curchar != 1 && curchar != 255)
    {
      fprintf (stderr, "Invalid SIC parameter (SIC = %x)\n", curchar);
    }
  else
    {
#ifdef DEBUG
      fprintf (stderr, "SIC = %x", curchar);
#ifdef VERBOSE
      fprintf (stderr, "\tInitializing for data processing");
#endif
      fprintf (stderr, "\n");
#endif
    }
  return;
}


/* Set Exception Action (SEA).  This is part of Device Control.  SEA
 * introduces a sequence of byte pairs.  The byte pairs have a length
 * of (curchar-2) bytes.  The first byte of each pair is the exception
 * class.  The second is the action.
 *
 * The exception class bytes has the following meanings:
 * 0 - all exception classes
 * 1-4 - classes 1-4 respectively
 * all others - invalid
 *
 * The action may be:
 * 0 - accept.  On the printer this is the same is ignore (1).
 * 1 - ignore
 * 2 - terminate
 * 3 - suspend
 *
 * If we get an action of 2 or 3 we should probably exit(), but for
 * now do nothing.
 */
void
scs_sea (Tn5250SCS * This)
{
  unsigned char exception;
  unsigned char action;
  int loop;

  for (loop = 0; loop < This->curchar - 2; loop++)
    {
      exception = fgetc (stdin);
      if (exception > 4)
	{
	  fprintf (stderr, "Invalid exception class (%d)\n", exception);
	}
      else
	{
#ifdef DEBUG
	  fprintf (stderr, "SEA (length %x) = %d", This->curchar, exception);
#endif
	}
      action = fgetc (stdin);
      if (action > 3)
	{
	  fprintf (stderr,
		   "Invalid action (exception class: %d, action %d)\n",
		   exception, action);
	}
      else
	{
#ifdef DEBUG
	  fprintf (stderr, " %d", action);
#ifdef VERBOSE
	  switch (action)
	    {
	    case 0:
	      {
		if (exception == 0)
		  {
		    fprintf (stderr,
			     "\tUsing action ACCEPT for exception class %d (all exception classes)",
			     exception);
		  }
		else
		  {
		    fprintf (stderr,
			     "\tUsing action ACCEPT for exception class %d",
			     exception);
		  }
		break;
	      }
	    case 1:
	      {
		if (exception == 0)
		  {
		    fprintf (stderr,
			     "\tUsing action IGNORE for exception class %d (all exception classes)",
			     exception);
		  }
		else
		  {
		    fprintf (stderr,
			     "\tUsing action IGNORE for exception class %d",
			     exception);
		  }
		break;
	      }
	    case 2:
	      {
		if (exception == 0)
		  {
		    fprintf (stderr,
			     "\tUsing action TERMINATE for exception class %d (all exception classes)",
			     exception);
		  }
		else
		  {
		    fprintf (stderr,
			     "\tUsing action TERMINATE for exception class %d",
			     exception);
		  }
		break;
	      }
	    case 3:
	      {
		if (exception == 0)
		  {
		    fprintf (stderr,
			     "\tUsing action SUSPEND for exception class %d (all exception classes)",
			     exception);
		  }
		else
		  {
		    fprintf (stderr,
			     "\tUsing action SUSPEND for exception class %d",
			     exception);
		  }
		break;
	      }
	    }
#endif
	  fprintf (stderr, "\n");
#endif
	}
      loop++;
    }
  return;
}


/* Null (NUL).  This is part of Device Control.
 * Don't do anything
 */
void
scs_noop (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "NOOP\n");
#endif
  return;
}


/* ASCII Transparency (ATRN).  This is part of Device Control.
 * Only used to send PCL codes to an ascii printer.
 */
void
scs_transparent (Tn5250SCS * This)
{
  int bytecount;
  int loop;

  bytecount = fgetc (stdin);
  fprintf (stderr, "TRANSPARENT (%x) = ", bytecount);
  for (loop = 0; loop < bytecount; loop++)
    {
      fprintf (stderr, "%c", fgetc (stdin));
    }
  return;
}


/* Set Print Setup (SPSU).  This is part of Device Control.  SPSU
 * selects the paper source tray.
 *
 * The documentation is a little weird on this on.  But we ignore it
 * anyway, so who cares?  Usually the host sends us 03 which means if
 * the printer is currently set to manual feed, use tray 1.
 */
void
scs_spsu (Tn5250SCS * This)
{
  unsigned char trayparm;
  unsigned char nextchar;
  int loop;

  nextchar = fgetc (stdin);
  trayparm = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SPSU (%x) = %x%x", This->curchar, nextchar, trayparm);
#endif
  for (loop = 2; loop < This->curchar - 2; loop++)
    {
      nextchar = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, " %x", nextchar);
#endif
    }
#ifdef DEBUG
#ifdef VERBOSE
  if (trayparm < 4)
    {
      switch (trayparm)
	{
	case 0:
	  {
	    fprintf (stderr, "\tPaper source tray left unchanged");
	    break;
	  }
	case 1:
	  {
	    fprintf (stderr, "\tPaper source tray set to manual");
	    break;
	  }
	case 2:
	  {
	    fprintf (stderr, "\tPaper source tray set to tray 1");
	    break;
	  }
	case 3:
	  {
	    fprintf (stderr, "\tPaper source tray set to tray 1");
	    break;
	  }
	}
    }
#endif
  fprintf (stderr, "\n");
#endif
  return;
}


/* Page Presentation Media (PPM).  This is part of Page Controls.
 * This also selects paper source - in seeming conflict with SPSU.
 */
void
scs_ppm (Tn5250SCS * This)
{
  unsigned char formscontrol, sourcedrawer, destdraweroffset;
  unsigned char destdrawer, quality, duplex;
  unsigned char nextchar;

#ifdef DEBUG
  fprintf (stderr, "Begin Page Presentation Media (PPM)\n");
  fprintf (stderr, "Length of PPM parameters: %d\n", This->curchar);
#endif
  nextchar = fgetc (stdin);
  nextchar = fgetc (stdin);
  formscontrol = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "\tForms control = %x\n", formscontrol);
#endif
  if (This->curchar > 5)
    {
      sourcedrawer = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, "\tSource drawer = %x\n", sourcedrawer);
#endif
    }
  if (This->curchar > 6)
    {
      destdraweroffset = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, "\tDestination drawer offset = %x\n",
	       destdraweroffset);
#endif
    }
  if (This->curchar > 7)
    {
      destdrawer = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, "\tDestination drawer = %x\n", destdrawer);
#endif
    }
  if (This->curchar > 8)
    {
      quality = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, "\tQuality = %x\n", quality);
#endif
    }
  if (This->curchar > 9)
    {
      duplex = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, "\tDuplex = %x\n", duplex);
#endif
    }
#ifdef DEBUG
  fprintf (stderr, "End Page Presentation Media (PPM)\n");
#endif
  return;
}


/* Set Presentation Page Size (SPPS).  This is part of Page Controls.
 * Sets the presetation surface width and optionally depth in units of
 * 1440ths of an inch.  Valid values are 0 - 32767.  A value of 0 results
 * in no change.
 *
 * Definately look at the IBM docs for this one.  Particularly note that
 * the presentation size can be different (even larger) than the actual
 * page size.
 */
void
scs_spps (Tn5250SCS * This)
{
  int width, length;

  width = fgetc (stdin);
  width = (width << 8) + fgetc (stdin);
  This->pagewidth = width;

  length = fgetc (stdin);
  length = (length << 8) + fgetc (stdin);
  This->pagelength = length;

#ifdef DEBUG
  fprintf (stderr, "SPPS (width = %d) (length = %d)", width, length);
#ifdef VERBOSE
  fprintf (stderr, "\tPrintable region is %d by %d inches",
	   (width / 1440), (length / 1440));
#endif
  fprintf (stderr, "\n");
#endif
  return;
}


/* Set Horizontal Format (SHF).  This is part of Page Controls.
 * Specifies the presentation surface width.
 */
void
scs_shf (Tn5250SCS * This)
{
  unsigned char shf1, shf2;

  shf1 = fgetc (stdin);
  shf2 = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SHF = %x %x\n", shf1, shf2);
#endif
  return;
}


/* Set Vertical Format (SVF).  This is part of Page Controls.
 * Specifies the presentation surface depth.
 */
void
scs_svf (Tn5250SCS * This)
{
  unsigned char svf1, svf2;

  svf1 = fgetc (stdin);
  svf2 = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SVF = %x %x\n", svf1, svf2);
#endif
  return;
}


/* Form Feed/page end (FF/PE).  This is part of Page Controls.
 * Prints the current page.
 */
void
scs_ff (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "FF\n");
#endif
  return;
}


/* Required Form Feed/page end (RFF/RPE).  This is part of Page Controls.
 * Prints the current page like form feed, but also restores the indent
 * level to the left margin
 */
void
scs_rff (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "RFF\n");
#endif
  return;
}


/* Set Text Orientation (STO).  This is part of Page Controls.
 * Sets the orientation of characters on a page.  It has two paramters:
 *
 * 2-byte parameter for character rotation.  This is always ignored.
 * 2-byte parameter for page rotation with the following meanings:
 *
 *   0000 - portrait
 *   2D00 - rotate clockwise 270 degrees
 *   5A00 - rotate clockwise 180 degrees
 *   8700 - rotate clockwise 90 degrees
 *   FFFE - select COR mode
 *   FFFF - calculate based on SPPS (default)
 *   all others - invalid
 */
void
scs_sto (Tn5250SCS * This)
{
  unsigned char charrot1;
  unsigned char charrot2;
  unsigned char pagerot1;
  unsigned char pagerot2;

#ifdef DEBUG
  fprintf (stderr, "STO = ");
#endif
  charrot1 = fgetc (stdin);
  charrot2 = fgetc (stdin);
  pagerot1 = fgetc (stdin);
  pagerot2 = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "%x%x %x%x", charrot1, charrot2, pagerot1, pagerot2);
#ifdef VERBOSE
  switch (pagerot1)
    {
    case 0x00:
      {
	fprintf (stderr, "\tPrinting normal portrait");
	break;
      }
    case 0x2D:
      {
	fprintf (stderr, "\tPrinting landscape left");
	break;
      }
    case 0x5A:
      {
	fprintf (stderr, "\tPrinting portrait upside down");
	break;
      }
    case 0x87:
      {
	fprintf (stderr, "\tPrinting landscape right");
	break;
      }
    case 0xFF:
      {
	if (pagerot2 == 0xFE)
	  {
	    fprintf (stderr, "\tSelected COR mode");
	  }
	else
	  {
	    fprintf (stderr,
		     "\tSetting text orientation based on SPPS command");
	  }
      }
    }
#endif
  fprintf (stderr, "\n");
#endif
  if (pagerot1 != 0xFF && pagerot2 != 0xFF)
    {
      fprintf (stderr, "Unhandled page rotation!!\n");
    }
  return;
}


/* Set Horizontal Margins (SHM).  This is part of Page Controls.
 * Sets the left margin and optionally the right margin in terms
 * of 1440ths of an inch from the left and optionally right edges
 * of the paper.  Valid values are 0 - 32767.  A value of 0 means
 * to leave the margins unchanged.
 */
void
scs_shm (Tn5250SCS * This)
{
  unsigned char left1;
  unsigned char left2;
  unsigned char right1;
  unsigned char right2;

  left1 = fgetc (stdin);
  left2 = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SHM = %d%d", left1, left2);
#endif
  if (This->curchar > 5)
    {
      right1 = fgetc (stdin);
      right2 = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, " %d%d", right1, right2);
#endif
#ifdef VERBOSE
      fprintf (stderr,
	       "\tSetting margins to %d%d 1440ths of an inch in from the left\n",
	       left1, left2);
      fprintf (stderr,
	       "\t\tedge and %d%d 1440ths of an inch in from the right edge",
	       right1, right2);
#endif
    }
#ifdef DEBUG
  fprintf (stderr, "\n");
#endif
  return;
}


/* Set Vertical Margins (SVM).  This is part of Page Controls.
 * Sets the top margin and optionally the bottom margin in terms
 * of 1440ths of an inch from the top and optionally bottom edges
 * of the paper.  Valid values are 0 - 32767.  A value of 0 means
 * to leave the margins unchanged.
 */
void
scs_svm (Tn5250SCS * This)
{
  unsigned char top1;
  unsigned char top2;
  unsigned char bottom1;
  unsigned char bottom2;

  top1 = fgetc (stdin);
  top2 = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SVM = %d%d", top1, top2);
#endif
  if (This->curchar > 5)
    {
      bottom1 = fgetc (stdin);
      bottom2 = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, " %d%d", bottom1, bottom2);
#ifdef VERBOSE
      fprintf (stderr,
	       "\tSetting margins to %d%d 1440ths of an inch in from the top\n",
	       top1, top2);
      fprintf (stderr,
	       "\t\tedge and %d%d 1440ths of an inch in from the bottom edge",
	       bottom1, bottom2);
#endif
#endif
    }
#ifdef DEBUG
  fprintf (stderr, "\n");
#endif
  return;
}


/* Set Form Feed Control (SFFC).  This is part of Page Controls.
 * Specifies the number of form feeds to be issued before a page is
 * printed.  It has one 1-byte parameter.  The default is 0x01. Valid
 * values are 0x00 - 0xFF.  0x00 means no change.
 */
void
scs_sffc (Tn5250SCS * This)
{
  unsigned char nextchar;

  nextchar = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SFFC=%x\n", nextchar);
#ifdef VERBOSE
  fprintf (stderr,
	   "\tRequiring %x form feeds to be issued before printing page\n",
	   nextchar);
#endif
  fprintf (stderr, "\n");
#endif
  return;
}


/* Set CGCS through Local ID (SCGL).  This is part of Font Controls.
 * This has a 1-byte parameter that gives the local ID.  The default
 * is 0xFF
 */
void
scs_scgl (Tn5250SCS * This)
{
  unsigned char nextchar;

  nextchar = fgetc (stdin);
  if (nextchar != 0xFF)
    {
      fprintf (stderr, "SCGL = %x\n", nextchar);
    }
  else
    {
#ifdef DEBUG
      fprintf (stderr, "SCGL = %x\n", nextchar);
#endif
    }
  return;
}


/* Set GCGID through GCID (SCG).  This is part of Font Controls.
 * Sets the code page.  This has two 1-byte parameters that give the
 * the graphic character set global ID (which is ignored) and the code
 * page global ID.  The second parameter selects the code page.
 * 
 * See the documentation for a complete table of valid values.
 */
void
scs_scg (Tn5250SCS * This)
{
  unsigned char gcgid;
  unsigned char cpgid;

  gcgid = fgetc (stdin);
  cpgid = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "GCGID = %d, CPGID = %d\n", gcgid, cpgid);
#endif
  return;
}


/* Set FID through GFID (SFG).  This is part of Font Controls.
 * Selects the font.  This has two 2-byte parameters and one 1-byte
 * parameter.
 */
void
scs_sfg (Tn5250SCS * This)
{
  unsigned char globalfontid1;
  unsigned char globalfontid2;
  unsigned char fontwidth1;
  unsigned char fontwidth2;
  unsigned char fontattribute;

  globalfontid1 = fgetc (stdin);
  globalfontid2 = fgetc (stdin);
  fontwidth1 = fgetc (stdin);
  fontwidth2 = fgetc (stdin);
  fontattribute = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "FID = %x%x %x%x %x\n", globalfontid1, globalfontid2,
	   fontwidth1, fontwidth2, fontattribute);
#endif
  return;
}


/* Set Character Distance (SCD).  This is part of Font Controls.
 * This is also known and Set Print Density (SPD).  This is the SCS
 * alternative method of selecting fonts.  This has one 2-byte parameter.
 * The following values are supported:
 *
 * 0x0000 - unchanged
 * 0x0005 - courier 5
 * 0x000A - courier 10
 * 0x000B - courier 12 proportionally spaced
 * 0x000C - courier 12
 * 0x000F - courier 15
 * 0x00FF - use font from operation panel
 * all others - invalid
 */
void
scs_scd (int *cpi)
{
  unsigned char chardist1;
  unsigned char chardist2;

  chardist1 = fgetc (stdin);
  chardist2 = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SCD = %x%x", chardist1, chardist2);
#endif
  /* Here we convert characters per inch (CPI) to point size.  In the
   * future we will probably want these to be user definable.
   */
  switch (chardist2)
    {
    case 0x05:
      {
	*cpi = 14;
#ifdef DEBUG
#ifdef VERBOSE
	fprintf (stderr, "\tFont set to Courier %d", *cpi);
#endif
#endif
	break;
      }
    case 0x0A:
      {
	*cpi = 10;
#ifdef DEBUG
#ifdef VERBOSE
	fprintf (stderr, "\tFont set to Courier %d", *cpi);
#endif
#endif
	break;
      }
    case 0x0B:
      {
	*cpi = 9;
#ifdef DEBUG
#ifdef VERBOSE
	fprintf (stderr, "\tFont set to Courier %d", *cpi);
#endif
#endif
	break;
      }
    case 0x0C:
      {
	*cpi = 10;
#ifdef DEBUG
#ifdef VERBOSE
	fprintf (stderr, "\tFont set to Courier %d", *cpi);
#endif
#endif
	break;
      }
    case 0x0F:
      {
	*cpi = 7;
#ifdef DEBUG
#ifdef VERBOSE
	fprintf (stderr, "\tFont set to Courier %d", *cpi);
#endif
#endif
	break;
      }
    default:
      {
	*cpi = 10;
#ifdef DEBUG
#ifdef VERBOSE
	fprintf (stderr, "\tFont set to Courier %d", *cpi);
#endif
#endif
	break;
      }
    }
#ifdef DEBUG
  fprintf (stderr, "\n");
#endif
  return;
}


/* Presentation Position (PP).  This is part of Cursor Controls.
 * Moves the current cursor position based on the given parameters.
 */
void
scs_pp (Tn5250SCS * This)
{
  unsigned char curchar;

  curchar = fgetc (stdin);
  switch (curchar)
    {
    case SCS_RDPP:
      {
	scs_rdpp (This);
	break;
      }
    case SCS_AVPP:
      {
	scs_avpp (This);
	break;
      }
    case SCS_AHPP:
      {
	scs_ahpp (This);
	break;
      }
    case SCS_RRPP:
      {
	scs_rrpp (This);
	break;
      }
    default:
      {
	fprintf (stderr, "ERROR: Unknown 0x34 command %x\n", curchar);
      }
    }
  return;
}


/* Relative move Down (RDPP).  This is part of Cursor Controls.
 */
void
scs_rdpp (Tn5250SCS * This)
{
  unsigned char rdpp;

  rdpp = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "RDPP %d\n", rdpp);
#endif
  return;
}


/* Absolute Horizontal move (AHPP).  This is part of Cursor Controls.
 */
void
scs_ahpp (Tn5250SCS * This)
{
  int position;
  int i;

  position = fgetc (stdin);

  if (This->row > position)
    {
      for (i = 0; i < position; i++)
	{
	  /* Each application needs to process its own way for adding
	   * spaces.  Add one space for each iteration
	   */
	  /*printf(" "); */
	}
    }
  else
    {
      for (i = 0; i < (position - This->row); i++)
	{
	  /* Each application needs to process its own way for adding
	   * spaces.  Add one space for each iteration
	   */
	  /*printf(" "); */
	}
    }
  This->row = position;

#ifdef DEBUG
  fprintf (stderr, "AHPP %d\n", position);
#endif
  return;
}


/* Absolute Vertical move (AVPP).  This is part of Cursor Controls.
 */
void
scs_avpp (Tn5250SCS * This)
{
  unsigned char nextchar;

  nextchar = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "AVPP %d\n", nextchar);
#endif
  return;
}


/* Relative move Right (RRPP).  This is part of Cursor Controls.
 */
void
scs_rrpp (Tn5250SCS * This)
{
  unsigned char nextchar;

  nextchar = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "RRPP %d\n", nextchar);
#endif
  return;
}


/* Subscript (SBS).  This is part of Cursor Controls.
 */
void
scs_sbs (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "SBS\n");
#endif
  return;
}


/* Superscript (SPS).  This is part of Cursor Controls.
 */
void
scs_sps (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "SPS\n");
#endif
  return;
}


/* New Line (NL).  This is part of Cursor Controls.
 */
void
scs_nl (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "NL\n");
#endif
  return;
}


/* Interchange Record Separator (IRS).  This is part of Cursor Controls.
 * This is the same as a new line control.
 */
void
scs_irs (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "IRS\n");
#endif
  return;
}


/* Required New Line (RNL).  This is part of Cursor Controls.
 */
void
scs_rnl (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "RNL\n");
#endif
  return;
}


/* Index Return (IRT).  This is part of Cursor Controls.
 * Processed as a required new line.
 */
void
scs_irt (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "IRT\n");
#endif
  return;
}


/* Set horizontal Tab stops (STAB).  This is part of Cursor Controls.
 * Set tab stops.  This has two parameters:  one 1-byte parameter that
 * indicates if the tabs are floating or fixed and one variable sized
 * parameter that defines the tab stops.
 */
void
scs_stab (Tn5250SCS * This)
{
  unsigned char nextchar;
  int loop;

#ifdef DEBUG
  fprintf (stderr, "STAB = ");
#endif
  for (loop = 0; loop < This->curchar - 2; loop++)
    {
      nextchar = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, " %x", nextchar);
#endif
    }
#ifdef DEBUG
  fprintf (stderr, "\n");
#endif
  return;
}


/* Horizontal Tab (HT).  This is part of Cursor Controls.
 * Moves the cursor to the right to the next tab stop.
 */
void
scs_ht (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "HT\n");
#endif
  return;
}


/* Indent Tab (IT).  This is part of Cursor Controls.
 * This is processed the same as horizontal tab except that the left
 * margin is moved to the nex tab stop.
 */
void
scs_it (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "IT\n");
#endif
  return;
}


/* Set Indent Level (SIL).  This is part of Cursor Controls.
 */
void
scs_sil (Tn5250SCS * This)
{
  unsigned char curchar;

  curchar = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SIL = %d", curchar);
#endif
  return;
}


/* Line Feed/index (LF).  This is part of Cursor Controls.
 * Moves the vertical position down one line increment.  The horizontal
 * position is unchanged.
 */
void
scs_lf (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "LF\n");
#endif
  return;
}


/* Carriage Return (CR).  This is part of Cursor Controls.
 * Moves the horizontal position to the left margin.  The vertical
 * position is unchanged.
 */
void
scs_cr (Tn5250SCS * This)
{
#ifdef DEBUG
  fprintf (stderr, "CR\n");
#endif
  return;
}

void
scs_process2b (Tn5250SCS * This)
{
  unsigned char curchar;

  curchar = fgetc (stdin);
  switch (curchar)
    {
    case 0xD1:
      {
	scs_processd1 ();
	break;
      }
    case 0xD2:
      {
	scs_processd2 (This);
	break;
      }
    case 0xD3:
      {
	scs_processd3 (This);
	break;
      }
    case 0xC8:
      {
	scs_sgea (This);
	break;
      }
    case 0xC1:
      {
	scs_shf (This);
	break;
      }
    case 0xC2:
      {
	scs_svf (This);
	break;
      }
    default:
      {
	fprintf (stderr, "ERROR: Unknown 0x2B command %x\n", curchar);
      }
    }
  return;
}

void
scs_processd3 (Tn5250SCS * This)
{
  unsigned char curchar;
  unsigned char nextchar;

  curchar = fgetc (stdin);
  This->curchar = curchar;
  nextchar = fgetc (stdin);

  if (nextchar == 0xF6)
    {
      scs_sto (This);
    }
  else
    {
      fprintf (stderr, "ERROR: Unknown 0x2BD3 %x %x", curchar, nextchar);
    }
  return;
}

void
scs_sgea (Tn5250SCS * This)
{
  unsigned char sgea1, sgea2, sgea3;

  sgea1 = fgetc (stdin);
  sgea2 = fgetc (stdin);
  sgea3 = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SGEA = %x %x %x\n", sgea1, sgea2, sgea3);
#endif
  return;
}

void
scs_processd1 ()
{
  unsigned char curchar;

  curchar = fgetc (stdin);
  switch (curchar)
    {
    case 0x06:
      {
	scs_process06 ();
	break;
      }
    case 0x07:
      {
	scs_process07 ();
	break;
      }
    case 0x03:
      {
	scs_processd103 ();
	break;
      }
    default:
      {
	fprintf (stderr, "ERROR: Unknown 0x2BD1 command %x\n", curchar);
      }
    }
  return;
}

void
scs_process06 ()
{
  unsigned char curchar;

  curchar = fgetc (stdin);
  if (curchar == 0x01)
    {
      scs_scg (NULL);
    }
  else
    {
      fprintf (stderr, "ERROR: Unknown 0x2BD106 command %x\n", curchar);
    }
  return;
}

void
scs_process07 ()
{
  unsigned char curchar;

  curchar = fgetc (stdin);
  if (curchar == 0x05)
    {
      scs_sfg (NULL);
    }
  else
    {
      fprintf (stderr, "ERROR: Unknown 0x2BD107 command %x\n", curchar);
    }
  return;
}

void
scs_processd103 ()
{
  unsigned char curchar;

  curchar = fgetc (stdin);
  switch (curchar)
    {
    case 0x81:
      {
	scs_scgl (NULL);
	break;
      }
    case 0x87:
      {
	scs_sffc (NULL);
	break;
      }
    default:
      {
	fprintf (stderr, "ERROR: Unknown 0x2BD103 command %x\n", curchar);
	break;
      }
    }
  return;
}

void
scs_processd2 (Tn5250SCS * This)
{
  unsigned char curchar;
  unsigned char nextchar;

  curchar = fgetc (stdin);
  This->curchar = curchar;
  nextchar = fgetc (stdin);


  switch (nextchar)
    {
    case 0x01:
      {
	scs_stab (This);
	break;
      }
    case 0x03:
      {
	scs_jtf (This->curchar);
	break;
      }
    case 0x0D:
      {
	scs_sjm (This->curchar);
	break;
      }
    case 0x40:
      {
	scs_spps (This);
	break;
      }
    case 0x48:
      {
	scs_ppm (This);
	break;
      }
    case 0x49:
      {
	scs_svm (This);
	break;
      }
    case 0x4c:
      {
	scs_spsu (This);
	break;
      }
    case 0x85:
      {
	scs_sea (This);
	break;
      }
    case 0x11:
      {
	scs_shm (This);
	break;
      }
    default:
      {
	switch (curchar)
	  {
	  case 0x03:
	    {
	      scs_process03 (nextchar, curchar);
	      break;
	    }
	  case 0x04:
	    {
	      scs_process04 (nextchar, curchar, &(This->cpi));
	      break;
	    }
	  default:
	    {
	      fprintf (stderr, "ERROR: Unknown 0x2BD2 command %x\n", curchar);
	    }
	  }
      }
    }
  return;
}

void
scs_jtf (unsigned char curchar)
{
  unsigned char nextchar;
  int loop;

#ifdef DEBUG
  fprintf (stderr, "JTF = ");
#endif

  for (loop = 0; loop < curchar - 2; loop++)
    {
      nextchar = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, " %x", nextchar);
#endif
    }
#ifdef DEBUG
  fprintf (stderr, "\n");
#endif
  return;
}

void
scs_sjm (unsigned char curchar)
{
  unsigned char nextchar;
  int loop;

#ifdef DEBUG
  fprintf (stderr, "SJM = ");
#endif

  for (loop = 0; loop < curchar - 2; loop++)
    {
      nextchar = fgetc (stdin);
#ifdef DEBUG
      fprintf (stderr, " %x", nextchar);
#endif
    }
#ifdef DEBUG
  fprintf (stderr, "\n");
#endif
  return;
}

void
scs_process03 (unsigned char nextchar, unsigned char curchar)
{
  switch (nextchar)
    {
    case 0x45:
      {
	scs_sic (NULL);
	break;
      }
    case 0x07:
      {
	scs_sil (NULL);
	break;
      }
    case 0x09:
      {
	scs_sls (NULL);
	break;
      }
    default:
      {
	fprintf (stderr, "ERROR: Unknown 0x2BD203 command %x\n", curchar);
      }
    }
  return;
}

void
scs_sls (Tn5250SCS * This)
{
  unsigned char curchar;

  curchar = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SLS = %d\n", curchar);
#endif
  return;
}

void
scs_process04 (unsigned char nextchar, unsigned char curchar, int *cpi)
{
  switch (nextchar)
    {
    case 0x15:
      {
	scs_ssld (NULL);
	break;
      }
    case 0x29:
      {
	scs_scd (cpi);
	/*scs_scs (cpi); */
	break;
      }
    default:
      {
	fprintf (stderr, "ERROR: Unknown 0x2BD204 command %x\n", curchar);
      }
    }
  return;
}

void
scs_ssld (Tn5250SCS * This)
{
  unsigned char curchar;
  unsigned char nextchar;

  curchar = fgetc (stdin);
  nextchar = fgetc (stdin);
#ifdef DEBUG
  fprintf (stderr, "SSLD = %d %d \n", curchar, nextchar);
#endif
  return;
}

/* This function is obsolete - scs_scd() should be used */
void
scs_scs (int *cpi)
{
  unsigned char curchar;

  fprintf (stderr, "scs_scs was called but is obsolete!!!\n");
  curchar = fgetc (stdin);
  if (curchar == 0x00)
    {
      curchar = fgetc (stdin);

      /* Here we convert characters per inch (CPI) to point size.  In the
       * future we will probably want these to be user definable.
       */
      switch (curchar)
	{
	case 5:
	  {
	    *cpi = 14;
	    break;
	  }
	case 10:
	  {
	    *cpi = 10;
	    break;
	  }
	case 12:
	  {
	    *cpi = 9;
	    break;
	  }
	case 13:
	  {
	    *cpi = 8;
	    break;
	  }
	case 15:
	  {
	    *cpi = 7;
	    break;
	  }
	case 16:
	  {
	    *cpi = 6;
	    break;
	  }
	case 18:
	  {
	    *cpi = 5;
	    break;
	  }
	case 20:
	  {
	    *cpi = 4;
	    break;
	  }
	default:
	  {
	    *cpi = 10;
	    break;
	  }
	}
#ifdef DEBUG
      fprintf (stderr, "SCS = %d\n", curchar);
#endif
    }
  else
    {
      fprintf (stderr, "ERROR: Unknown 0x2BD20429 command %x\n", curchar);
    }
  return;
}


void
scs_default (Tn5250SCS * This)
{
  printf ("%c", This->curchar);
  return;
}


/* scs_main - reads the scs stream and calls functions to handle events
 */
void
scs_main (Tn5250SCS * This)
{
  int curchar;

  while ((curchar = fgetc (stdin)) != EOF)
    {
      This->curchar = curchar;
#ifdef DEBUG
      fprintf (stderr, "%x ", This->curchar);
#endif
      switch (This->curchar)
	{
	case SCS_TRANSPARENT:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing TRANSPARENT\n");
#endif
	    This->transparent (This);
	    break;
	  }
	case SCS_NOOP:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing NOOP\n");
#endif
	    This->noop (This);
	    break;
	  }
	case SCS_CR:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing CR\n");
#endif
	    This->cr (This);
	    break;
	  }
	case SCS_FF:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing FF\n");
#endif
	    This->ff (This);
	    break;
	  }
	case SCS_RFF:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing RFF\n");
#endif
	    This->rff (This);
	    break;
	  }
	case SCS_NL:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing NL\n");
#endif
	    This->nl (This);
	    break;
	  }
	case SCS_RNL:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing RNL\n");
#endif
	    This->rnl (This);
	    break;
	  }
	case SCS_HT:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing HT\n");
#endif
	    This->ht (This);
	    break;
	  }
	case SCS_PP:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing PP\n");
#endif
	    This->pp (This);
	    break;
	  }
	case 0x2B:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing 2B\n");
#endif
	    This->process2b (This);
	    break;
	  }
	case 0xFF:
	  {
	    /* This is a hack */
	    /* Don't know where the 0xFF is coming from */
	    fprintf (stderr, "Unhandled op 0xFF\n");
	    break;
	  }
	default:
	  {
#ifdef DEBUG
	    fprintf (stderr, "doing scsdefault()\n");
#endif
	    This->scsdefault (This);
	    break;
	  }
	}

    }
  return;
}


/* This initializes the scs callbacks
 */
Tn5250SCS *
tn5250_scs_new ()
{
  Tn5250SCS *scs = tn5250_new (Tn5250SCS, 1);

  if (scs == NULL)
    {
      return NULL;
    }

  scs->sic = scs_sic;
  scs->sea = scs_sea;
  scs->noop = scs_noop;
  scs->transparent = scs_transparent;
  scs->spsu = scs_spsu;
  scs->ppm = scs_ppm;
  scs->spps = scs_spps;
  scs->shf = scs_shf;
  scs->svf = scs_svf;
  scs->ff = scs_ff;
  scs->rff = scs_rff;
  scs->sto = scs_sto;
  scs->shm = scs_shm;
  scs->svm = scs_svm;
  scs->sffc = scs_sffc;
  scs->scgl = scs_scgl;
  scs->scg = scs_scg;
  scs->sfg = scs_sfg;
  scs->scd = scs_scd;
  scs->pp = scs_pp;
  scs->sbs = scs_sbs;
  scs->sps = scs_sps;
  scs->nl = scs_nl;
  scs->irs = scs_irs;
  scs->rnl = scs_rnl;
  scs->irt = scs_irt;
  scs->stab = scs_stab;
  scs->ht = scs_ht;
  scs->it = scs_it;
  scs->sil = scs_sil;
  scs->lf = scs_lf;
  scs->cr = scs_cr;
  scs->ssld = scs_ssld;
  scs->sls = scs_sls;
  scs->sgea = scs_sgea;
  scs->process2b = scs_process2b;
  scs->scsdefault = scs_default;
  scs->pagewidth = 0;
  scs->pagelength = 0;
  scs->cpi = 0;
  scs->column = 0;
  scs->row = 0;
  scs->curchar = 0;
  scs->data = NULL;
  return scs;
}


syntax highlighted by Code2HTML, v. 0.9.1