/*  Copyright (C) 1987- Leon Bottou
 *
 *  This is free documentation; you can redistribute it and/or
 *  modify it under the terms of the GNU General Public License as
 *  published by the Free Software Foundation; either version 2 of
 *  the License, or (at your option) any later version.
 *
 *  The GNU General Public License's references to "object code"
 *  and "executables" are to be interpreted as the output of any
 *  document formatting or typesetting system, including
 *  intermediate and printed output.
 *
 *  This manual 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 General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public
 *  License along with this manual. Otherwise check the web site
 *  of the Free Software Foundation at http://www.fsf.org.
 */
/*
  CRASM: output.c
  sorties des listings
  LYB 9/87
*/

#include "dcl.h"
#include "version.h"
#include <ctype.h>

#define NMARGIN 21
#define LMARGIN 28

/*
  output(s)
  position(n);
  outputEOL()
  outputEOP()
  outputline()
  outputraw(s)
  settitle(s)
*/

static int lastoffset;

extern unsigned int chars_consumed_by_filter;
char linebuffer[1000];
char title[31] = "";
int pagenumber = 0;


void settitle(char* s)
{
  static byte flag = 0;

  if (flag)
  {
    crasm_warning("title redefinition");
  }

  if (strlen(s) > 30)
  {
    crasm_error("too long title");
  }

  strcpy(title, s);

  if (passnumber == 2)
  {
    flag = 1;
  }
}


void setpage(int xplen, int xllen)
{
  static byte flag = 0;

  if (flag)
  {
    crasm_warning("page redefinition");
  }

  if (xplen > 200 || (xplen && xplen < 10) || xllen < 39 || xllen > (int)sizeof(linebuffer))
  {
    crasm_error("illegal values");
  }

  plen = xplen;
  llen = xllen;

  if (passnumber == 2)
  {
    flag = 1;
  }
}


void outputraw(char* s)
{
  register int i;

  if (asmflags & F_LIST_ON)
  {
    if (ppos == 0)
    {
      printf("Crasm %s:   %30s", CRASMVERSION, title);

      for (i = 58; i < llen; i++)
      {
        putchar(' ');
      }

      printf("page%3d\n\n", ++pagenumber);
      ppos = 2;
    }

    puts(s);

    ppos++;

    if (ppos >= plen - 2 && plen)
    {
      printf("\n\n");
      ppos = 0;
    }
  }

  if (ferror(stdout))
  {
    fileerror("output");
  }
}


void outputEOP(void)
{
  if (asmflags & F_LIST_ON)
  {
    if (plen)
    {
      while (ppos)
      {
        outputEOL();
      }
    }
    else
    {
      printf("\n\n\n");
    }
  }
}


static char* outpat[] = { "_? _? _?", "_? _?", "_?", NULL };

void output(char* s)
{
  while (*s)
  {
    outputcar(*s++);
  }
}


void outputcar(char c)
{
  char* dummy;
  char** pat;

  if (!isspace((unsigned char)c))
  {
    if (lpos >= llen)
    {
      outputEOL();

      if (filter(linebuffer + LMARGIN, "?;_?", &dummy, &dummy))
        /* suite de commentaire */
      {
        position(chars_consumed_by_filter);
      }
      else if (c == ';')
        /* debut de commentaire */
      {
        position(LMARGIN);
      }
      else if (lastoffset >= LMARGIN)
      {
        position(lastoffset);
      }
      else if (c != ';')

        /* suite d'un champ quelconque */
        for (pat = outpat; *pat; pat++)
        {
          if (filter(linebuffer + LMARGIN,
                     *pat,
                     &dummy, &dummy, &dummy))
          {
            position(chars_consumed_by_filter);
            break;
          }
        }

      lastoffset = lpos;
    }

    if (isprint((unsigned char)c) || (((unsigned char)c & 0x80) != 0))
    {
      linebuffer[lpos++] = c;
    }

    linebuffer[lpos] = 0;
  }
  else if (c == ' ')
  {
    if (lpos < llen)
    {
      linebuffer[lpos++] = ' ';
      linebuffer[lpos] = 0;
    }
    else
    {
      lpos++;
    }
  }
  else if (c == '\t')
  {
    do
    {
      outputcar(' ');
    } while ((lpos - LMARGIN) % 8);
  }
}


void position(int n)
{
  if (n >= llen)
  {
    crasm_fatal("line length must be greater");
  }

  while (lpos < n)
  {
    outputcar(' ');
  }
}


void outputEOL(void)
{
  outputraw(linebuffer);
  lpos = 0;
  *linebuffer = 0;
}


/* peut etre ameliore pour tabuler automatiquement */
void outputline(void)
{
  char linnum[10];
  register int i;

  lastoffset = 0;

  if (linenumber == 0)
  {
    return; /* special pour les include.. */
  }

  if (lineprefix)
  {
    sprintf(linnum, "     ");
    i = 5 - macrolevel;

    if (i < 0)
    {
      i = 0;
    }

    if (i > 4)
    {
      i = 4;
    }

    linnum[i] = lineprefix;
  }
  else
  {
    sprintf(linnum, "%5d", linenumber);
  }

  position(NMARGIN);
  output(linnum);
  position(LMARGIN);
  output(curline);
  outputEOL();
}


/* special output */

char hexa[] = "0123456789ABCDEF";
extern unsigned long pc;

void outputbyte(int b)
{
  char buffer[3];
  static unsigned long mypc;

  if (advance > 20 && lpos > NMARGIN - 5)
  {
    if (lpos <= NMARGIN - 3)
    {
      output("...");
    }

    return;
  }

  if (lpos > NMARGIN - 3)
  {
    outputEOL();
  }

  if (pc != mypc && lpos != 0)
  {
    outputEOL();
  }

  if (lpos == 0)
  {
    outputaddr(pc);
  }

  buffer[0] = hexa[(b >> 4) & 0xF];
  buffer[1] = hexa[b & 0xF];
  buffer[2] = 0;
  output(buffer);
  mypc = pc + 1;
}


void outputaddr(unsigned long a)
{
  char buffer[20];
  register int i;
  register char* s;

  s = buffer;
  i = 28;

  if (asmflags & F_ADDR24)
  {
    i = 20;
  }
  else if (asmflags & F_ADDR16)
  {
    i = 12;
  }

  for (;  i >= 0; i -= 4)
  {
    *s++ = hexa [(a >> i) & 0xF ];
  }

  *s++ = ' ';
  *s  = 0 ;

  output(buffer);
}

