/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 30-Nov-85 | [1.58] Created
*  6-Dec-85 | [1.145] In recognition of binary mode file, add \r to various
*           | listing print places
* 24-Nov-91 | [1.177] <jmn> converted to C6.0
* 26-Nov-91 | [1.196] <jmn> added err_multiply_defined
* 26-Nov-91 | [1.210] <jmn> added phase error
* 29-Nov-91 | [1.220] <jmn> added LIST, ULST operations
*  5-Dec-91 | [1.242] <jmn> JOB card causes page eject if anything is on the
*           | page
*****************************************************************************/

#include <stdio.h>
#include <boolean.h>
#include <time.h>
#include <string.h>

#include <error.h>
#include <err.h>
#include <list.h>
#include <operand.h>
#include <operands.h>
#include <bcd.h>
#include <pr.h>
#include <printers.h>
#include <expr.h>

static char buffer[255];	/* print buffer */
extern boolean pr64;


/* Listing format:

XXXXX XXX DDDDDDDD   LLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLLL
addr1 addr2 ldata    lline
*/

static char addr1[6];
static char addr2[4];
static char ldata[9];
static char err_L = ' ';
static char err_O = ' ';
static char err_D = ' ';

#define lline_length 55
static char lline[lline_length+1];

static char lline_fmt[20]= "";

extern char line[81];
extern FILE * listing;
extern boolean debug;
extern char filename[80];

static boolean needFF;
static int page;
static int printline;

static char * jobname = NULL;
static char * jobtitle = NULL;

static boolean islisting = true;
static boolean spacing = 1;
#define PAGELENGTH 55
static boolean blankpage = true;

/****************************************************************************
*                                   setjob
* Inputs:
*       char * name: Name string
*	char * title: Title to print on listing 
* Effect: 
*       sets up the local variables
****************************************************************************/

void setjob(char * name,char * title)
    {
     jobname = name;
     jobtitle = title;
     if(!blankpage)
	pageheading();
    }

/****************************************************************************
*                                   listop
* Inputs:
*       int opindex: Index of operation (not used)
*	int pass: Pass #, 1 or 2 (not used)
* Result: void
*       
* Effect: 
*       Turns on listing
****************************************************************************/

void listop(int opindex, int pass)
    {
     islisting = true;
    }

/****************************************************************************
*                                   ulstop
* Inputs:
*       int opindex: Index of operation (not used)
*	int pass: Pass #, 1 or 2 (not used)
* Result: void
*       
* Effect: 
*       Turns off listing
****************************************************************************/

void ulstop(int opindex, int pass)
    {
     islisting = false;
    }

/****************************************************************************
*                                 pageheading
* Effect: 
*       Writes page heading to output file
****************************************************************************/

void pageheading()
    {
     char date[60];
     char fname[80];
     time_t now;
     struct tm * tmnow;

     time(&now);
     tmnow = localtime(&now);

     strftime(date, sizeof(date), "%A, %d-%b-%y %H:%M:%S",tmnow);

     strcpy(fname,filename);

     strupr(date);	/* convert to uppercase */

     strupr(fname);	/* convert to uppercase */


     page++;

     if(needFF) 
	fprintf(listing,"\f");

     needFF = true;
     blankpage = true;

     fprintf(listing,"MINI-AUTOCODER %-22s %-32s Page %d\r\n",
     			fname,date,page);
     printline = 2;

     if(jobtitle != NULL)
        { /* print title */
	 fprintf(listing,"%-6s         %s\r\n",jobname,jobtitle);
	 printline++;
	} /* print title */

     fprintf(listing,"\r\n");
     printline++;

    }

/****************************************************************************
*                                clear_fields
* Effect: 
*       Clears the listing fields
****************************************************************************/

void clear_fields()
    {
     int i;

     err_L = ' ';
     err_O = ' ';
     err_D = ' ';

     for(i=0;i<8;i++) ldata[i] = ' ';

     sprintf(addr1,"     ");
     sprintf(addr2,"   ");
    }

/****************************************************************************
*                                init_listing
* Effect: 
*       Initializes the listing fields
****************************************************************************/

void init_listing()
    {
     sprintf(lline_fmt,"%%.%ds",lline_length);
     clear_fields();
     needFF = false;
     page = 0;
     printline = PAGELENGTH + 1;	/* force new page */
     islisting = true;
     spacing = 1;
    }

/****************************************************************************
*                                 end_listing
* Effect: 
*       Writes terminal ff to listing
****************************************************************************/

void end_listing()
    {
     fprintf(listing,"\f");
    }

/****************************************************************************
*                                  list_err
* Inputs:
*       int code: Error code
* Effect: 
*       Sets up the error flags
****************************************************************************/

void list_err(int code)
    {
     switch(code)
        { /* decode error */
	 case err_opcode:
	 		err_O = 'O';
			break;
	 case err_phase:
	 case err_label:
	 		err_L = 'L';
			break;
         case err_operand:
	 		err_D = 'E';
			break;
	 case err_multiply_defined:
		 	err_L = 'M';
			break;
	 default:
	 		err_D = '?';
			break;
	} /* decode error */
    }

/****************************************************************************
*                                  list_addr
* Inputs:
*       unsigned addr: Address to list
* Effect: 
*       Writes the address into the output listing
****************************************************************************/

unsigned list_addr(unsigned addr)
    {
     char bcd_addr[4];
     int i;

     cvbytes(bcd_addr,addr);
     bcd_addr[3]='\0';
     sprintf(addr1,"%5d",unindexed(addr));
     for(i=0;i<3;i++) addr2[i]= bcd_to_ascii(bcd_addr[i]);
     addr2[i] = '\0';
    }

/****************************************************************************
*                                  list_line
* Effect: 
*       Lists the input line to the listing
****************************************************************************/

void list_line()
    {
     if(debug)
        { /* list */
	 printf("list_line: fmt = \"%s\"\n",lline_fmt);
	 printf("list_line: line = \"%.55s\"\n",line);
	} /* list */
     sprintf(lline,lline_fmt,line);
    }

/****************************************************************************
*                                  list_lit
* Inputs:
*       char * lit: Literal to list
* Effect: 
*       Puts the literal in the operand line
****************************************************************************/

void list_lit(char * lit)
    {
     char l[200];

     sprintf(l,"           LTRL %s",lit);

     sprintf(lline,lline_fmt,l);
    }

/****************************************************************************
*                                  list_var
* Inputs:
*	char * name: Name of variable
*	int size: Size of variable
* Result: void
*       
* Effect: 
*       Lists the variable which was declared as name#size, e.g.,
*		NAME#6
*	is now dumped as
*	NAME   DCW  #6
****************************************************************************/

void list_var(char * name, int size)
    {
     char l[200];

     sprintf(l,"%-6.6s DCW   #%d",name,size);

     sprintf(lline,lline_fmt,l);
    }

/****************************************************************************
*                                check_heading
* Effect: 
*       If printline > pagelength forces new page heading
*	Increments printline variable
****************************************************************************/

void check_heading()
    {
     if(printline > PAGELENGTH) pageheading();
     printline++;

    }

/****************************************************************************
*                                emit_listing
* Effect: 
*       Writes the listing to the output file
****************************************************************************/

void emit_listing()
    {
     int i;

     if(islisting)
        { /* do listing */

	 check_heading();

	 for(i=strlen(lline)-2;i>0;i--)
	    if(lline[i] == ' ')
		lline[i] = '\0';
	    else
		break;

	 ldata[8] = '\0';

	 if(pr64)
	    { /* full glory */

	     sprintf(buffer,"%s %s %s %c%c%c  %s\r\n",
		    addr1, addr2, ldata, err_L, err_O, err_D, lline);

	     write_translated(buffer);

	    } /* full glory */
	 else
	    { /* fast and simple */
	     fprintf(listing,"%s %s %s %c%c%c  %s\r\n",
		    addr1, addr2, ldata, err_L, err_O, err_D, lline);
	    } /* fast and simple */

	 blankpage = false;

	 for(i=1; i<spacing; i++)
	    fprintf(listing,"\r\n");
	} /* do listing */
     clear_fields();
    }

/****************************************************************************
*                                   spceop
* Inputs:
*       int opindex: ignored
*	int pass: 1 or 2 (works only on pass 2)
* Result: void
*       
* Effect: 
*       Spaces up by operand # of lines
****************************************************************************/

void spceop(int opindex, int pass)
    {
     int i;
     unsigned n = 0;
     int noperands = 0;
     if(pass != 2)
	return;
     
     noperands = scan_operands();
     if(noperands != 1)
        { /* syntax error */
	 error(err_operand,"SPCE takes one and only one operand");
	 return;
	} /* syntax error */
     if(!expr(operands[0],&n,true,expr_lit_illegal,pass,false))
	return;
     switch(n)
        { /* what spacing? */
	 case 1:
	 case 2:
	 case 3:
		 spacing = n;
		 break;
	 default:
		 error(err_operand,"Illegal value for SPCE: 1,2,3 are only valid values");
		 break;
	} /* what spacing? */
    }

/****************************************************************************
*                                  put_data
* Inputs:
*       int i: Position for data in data field
*	char d: ASCII data character
* Effect: 
*       Writes the character d in the ith data field position
****************************************************************************/

void put_data(int i,char d)
    {
     if(i<0 || i>7)
        { /* error */
	 printf("putdata(%d,%d ('%c')) illegal offset %d\n",
	 		i,d,d,i);
	} /* error */
	 
     ldata[i] = d;
    }
