/*
	The FreeDOS Standart ANSI Colored Text Viewer.
	Copyright (C) 2002 Sandul Yura Valentinovich.
	This program is free software; 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.
	This program 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 program; if not, write to the Free Software Foundation, Inc., 675
Mass Ave, Cambridge, MA 02139, USA.
	Compiled using the Borland (R) Turbo-C v2.0.
*/

#include <stdio.h>         /* Include the ANSI-C standart functions headers. */
#include <conio.h>         /* Include the ANSI-C standart functions headers. */
int parameters[8];                     /* Parameters for the ANSI sequences. */
int parameterscount;                  /* Count of ANSI sequences parameters. */
int cursorx;                    /* Variable for save cursor column position. */
int cursory;                       /* Variable for save cursor row position. */
int cursorsave;                              /* Saved cursor positions flag. */
int outmode;                                         /* Symbol parsing mode. */
int colorattribute;                             /* Color attribute variable. */
char numberline[2];             /* Variable for number parameters charsters. */
void clearparameters()            /* Function for clear all ANSI parameters. */
{
 char index;                      /* Index variable for the clearing repeat. */
 parameterscount=0;                               /* Clear parameters count. */
 for(index=0;index<8;index++)parameters[index]=0;   /* Clear the parameters. */
}
void ansi(char charster)                        /* Parse symbols subroutine. */
{
 char index;                                  /* Index variable for repeats. */
 switch(outmode)                                   /* Select the parse mode. */
 {
  case 0:                                        /* Mode 0: Main parse mode. */
   switch(charster)                                  /* Select the charster. */
   {
    case 27:        /* If the escape code, then switch to escape parse mode. */
     outmode=1;                                /* Set the escape parse mode. */
     break;                           /* Break out from the switch operator. */
    case 10:                                                 /* End of line. */
     puts("");                                           /* Insert new line. */
     break;                           /* Break out from the switch operator. */
    case 9:                                                   /* Tab symbol. */
     putch(9);                                      /* Write the tab symbol. */
     break;                           /* Break out from the switch operator. */
    default:                                     /* Other printed charsters. */
     if(charster>31)putch(charster);                    /* Out the charster. */
   }
   break;                             /* Break out from the switch operator. */
  case 1:                                                 /* Mode 1: Escape. */
   switch(charster)                                  /* Select the charster. */
   {
    case '[':     /* If is the open parenthis charster, switch to next mode. */
     outmode=2;                      /* Switch to ANSI sequences parse mode. */
     break;                           /* Break out from the switch operator. */
    default:                    /* If other symbols, assert the escape mode. */
     outmode=0;                           /* Set mode to 0: Main parse mode. */
     ansi(charster);                /* Recursive call to write the charster. */
   }
   break;                             /* Break out from the switch operator. */
  case 2:                               /* Mode 2: The ANSI sequences parse. */
   switch(charster)                         /* Select the sequence charster. */
   {
    case '0':                                                     /* Digits. */
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
     clearparameters();                       /* Clear all exist parameters. */
     parameterscount=1;                      /* Set parameters count to one. */
     outmode=3;                             /* Set parse mode to 3: Digital. */
     for(index=0;index<2;index++)numberline[index]=0;      /* Clear numbers. */
     ansi(charster);                   /* Recursive call to get fisrt digit. */
     break;                           /* Break out from the switch operator. */
    case 's':            /* ANSI sequence 's': Save current cursor position. */
     if(cursorsave==0)        /* Check to previously saving cursor position. */
     {
      cursorx=wherex();                       /* Save current cursor column. */
      cursory=wherey();                          /* Save current cursor row. */
      cursorsave=1;                         /* Set saved cursor flag to one. */
     }
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'u':                 /* ANSI sequence 'u': Restore cursor position. */
     if(cursorsave==1)                       /* Check for saved cursor flag. */
     {
      gotoxy(cursorx,cursory);      /* Restore the previous cursor position. */
      cursorx=cursory=cursorsave=0;           /* Clear the cursor variables. */
     }
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'J':                        /* ANSI sequence 'J': Clear the screen. */
     clrscr();                                          /* Clear the screen. */
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'H':                    /* ANSI sequences 'H' and 'f': Move cursor. */
    case 'f':
		/* If one or two parameter(s) is not present, set it to one. */
     for(index=0;index<2;index++)if(parameters[index]==0)parameters[index]=1;
     gotoxy(parameters[1],parameters[0]);         /* Change cursor position. */
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'K':                    /* Ansi sequence 'K': Clear to end of line. */
     clreol();                                      /* Clear to end of line. */
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'A':                       /* ANSI sequence 'A': Move cursor to up. */
     if(parameters[0]==0)parameters[0]=1; /* If parameter not exist, set it. */
                           /* If cursor is not change normal range, move it. */
     if((wherey()-parameters[0])>0)gotoxy(wherex(),wherey()-parameters[0]);
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'B':                     /* ANSI sequence 'B': Move cursor to down. */
     if(parameters[0]==0)parameters[0]=1; /* If parameter not exist, set it. */
                           /* If cursor is not change normal range, move it. */
     if((wherey()+parameters[0])<26)gotoxy(wherex(),wherey()+parameters[0]);
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'C':                    /* ANSI sequence 'C': Move cursor to right. */
     if(parameters[0]==0)parameters[0]=1; /* If parameter not exist, set it. */
                           /* If cursor is not change normal range, move it. */
     if((wherex()+parameters[0])<81)gotoxy(wherex()+parameters[0],wherey());
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'D':                    /* ANSI sequence 'C': Move cursor to right. */
     if(parameters[0]==0)parameters[0]=1; /* If parameter not exist, set it. */
                           /* If cursor is not change normal range, move it. */
     if((wherex()-parameters[0])>0)gotoxy(wherex()-parameters[0],wherey());
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    case 'm':                     /* ANSI sequence 'm': Set color attribute. */
     if(parameterscount>0)             /* Check for presents the parameters. */
     {
      for(index=0;index<parameterscount;index++)  /* Parse exist parameters. */
      {
       switch(parameters[index])             /* Parse concretelly parameter. */
       {
        case 0:                           /* Attribute 0: Set gray on black. */
         colorattribute=(colorattribute&0x00)|0x07;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 1:                          /* Attribute 1: Set high intensity. */
         colorattribute=(colorattribute&0xff)|0x08;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 4:                               /* Attribute 4: Set underline. */
         colorattribute=(colorattribute&0xf8)|0x01;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 5:                                /* Attribute 5: Set blinking. */
         colorattribute=(colorattribute&0xff)|0x80;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 7:                                  /* Attribute 7: Set invert. */
         colorattribute=(colorattribute&0xf8)|0x70;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 8:                          /* Attribute 8: Set black on black. */
         colorattribute=(colorattribute&0x88)|0x00;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 30:                            /* Attribute 30: Set black text. */
         colorattribute=(colorattribute&0xf8)|0x00;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 31:                              /* Attribute 31: Set red text. */
         colorattribute=(colorattribute&0xf8)|0x04;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 32:                            /* Attribute 32: Set green text. */
         colorattribute=(colorattribute&0xf8)|0x02;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 33:                            /* Attribute 33: Set brown text. */
         colorattribute=(colorattribute&0xf8)|0x06;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 34:                             /* Attribute 34: Set blue text. */
         colorattribute=(colorattribute&0xf8)|0x01;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 35:                          /* Attribute 35: Set magenta text. */
         colorattribute=(colorattribute&0xf8)|0x05;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 36:                             /* Attribute 36: Set cyan text. */
         colorattribute=(colorattribute&0xf8)|0x03;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 37:                             /* Attribute 37: Set gray text. */
         colorattribute=(colorattribute&0xf8)|0x07;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 40:                      /* Attribute 40: Set black background. */
         colorattribute=(colorattribute&0x8f)|0x00;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 41:                        /* Attribute 41: Set red background. */
         colorattribute=(colorattribute&0x8f)|0x40;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 42:                      /* Attribute 42: Set green background. */
         colorattribute=(colorattribute&0x8f)|0x20;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 43:                      /* Attribute 43: Set brown background. */
         colorattribute=(colorattribute&0x8f)|0x60;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 44:                       /* Attribute 44: Set blue background. */
         colorattribute=(colorattribute&0x8f)|0x10;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 45:                    /* Attribute 45: Set magenta background. */
         colorattribute=(colorattribute&0x8f)|0x50;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 46:                       /* Attribute 46: Set cyan background. */
         colorattribute=(colorattribute&0x8f)|0x30;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
        case 47:                       /* Attribute 47: Set gray background. */
         colorattribute=(colorattribute&0x8f)|0x70;        /* Set attribute. */
         break;                       /* Break out from the switch operator. */
       }
       textattr(colorattribute);              /* Accept the color attribute. */
      }
     } else                 /* If parameters is not present, set to default. */
     {
      colorattribute=(colorattribute&0x00)|0x07;       /* Set gray on black. */
      textattr(colorattribute);               /* Accept the color attribute. */
     }
     clearparameters();                       /* Clear all exist parameters. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     break;                           /* Break out from the switch operator. */
    default:                                    /* Other charster: write it. */
     outmode=0;                     /* Set parse mode to 0: Main parse mode. */
     ansi(charster);                    /* Recursive call to write charster. */
     break;                           /* Break out from the switch operator. */
   }
   break;                             /* Break out from the switch operator. */
  case 3:                                           /* Mode 3: Digital mode. */
   switch(charster)                                      /* Select charster. */
   {
    case '0':                                                     /* Digits. */
    case '1':
    case '2':
    case '3':
    case '4':
    case '5':
    case '6':
    case '7':
    case '8':
    case '9':
    /* If null charster in parameter line, set first charster to own,
    if one charster is present, set second charster to own, else
    if number line is full (two charsters), skipp adding the charster.       */
     if(numberline[0]==0)numberline[0]=charster;
     else if(numberline[1]==0)numberline[1]=charster;
     break;                           /* Break out from the switch operator. */
    case ';':                                         /* Parameters divider. */
                     /* If parameters table is not full, then add parameter. */
     if(parameterscount<9)
     {
      if(numberline[1]!=0)              /* Evaluating the parameter meaning. */
      parameters[parameterscount-1]=((numberline[0]-'0')*10)+(numberline[1]-'0');
      else parameters[parameterscount-1]=numberline[0]-'0';
     }
                                                    /* Clear parameter line. */
     for(index=0;index<2;index++)numberline[index]=0;
     if(parameterscount<9)parameterscount++;  /* Change count of parameters. */
     break;                           /* Break out from the switch operator. */
    default:                                              /* Other charster. */
     if(parameterscount<9)                /* If parameter table is not full. */
     {
      if(numberline[1]!=0)              /* Evaluating the parameter meaning. */
      parameters[parameterscount-1]=((numberline[0]-'0')*10)+(numberline[1]-'0');
      else parameters[parameterscount-1]=numberline[0]-'0';
     }
                                                    /* Clear parameter line. */
     for(index=0;index<2;index++)numberline[index]=0;
              /* If parameters table is full, set the real parameters count. */
     if(parameterscount==9)parameterscount=8;
     outmode=2;            /* Set parse mode to 2: The ANSI sequences parse. */
     ansi(charster);           /* Recursive call to parse the ANSI sequence. */
   }
 }
}
void main(int argc,char *argv[])               /* The main program function. */
{
 FILE *ansifile;                                      /* Text file for show. */
 char ansicharster;
 clearparameters();                 /* Initizlize ANSI parameters variables. */
			       /* Clear the number line parameters charsters.*/
 for(ansicharster=0;ansicharster<2;ansicharster++)numberline[ansicharster]=0;
 cursorsave=cursorx=cursory=outmode=0;            /* Initializing variables. */
 colorattribute=(colorattribute&0x00)|0x07;    /* Set start color attribute. */
 textmode(C80);               /* Set screen mode to: text, 80x25, 16 colors. */
 directvideo=0;                   /* Turn off hardware direct screen output. */
 window(1,1,80,25);                            /* Set window to full screen. */
 textattr(colorattribute);             /* Accept the screen color attribute. */
 clrscr();                                              /* Clear the screen. */
		   /* Puts the copyright and information message text lines. */
 puts("The FreeDOS Standart ANSI colored text files viewer.");
 puts("(C) Copyright by Sandul Yura Valentinovich.");
 puts("(R) Monday, 20 May 2002 year.");
 puts("All rights reserved.");
 puts("*** FreeWare ***");
 puts("");
 puts("You can view DOS text CR-LF files ans Unix text LF files.");
 puts("Syntax: ANSI ANSIFile.Ans or more simplest: ANSI.");
 puts("");
 putchar(' ');
 for(ansicharster=0;ansicharster<78;ansicharster++)putchar('*');
 if(argc>2)              /* If arguments is too many, put the error message. */
 {
  puts("Arguments-count mismatch.");           /* Put the message text line. */
  return;                                                  /* Return to DOS. */
 }
 if(argc<2)       /* If arguments is too many, read file name from keyboard. */
 {
					     /* Put the information message. */
  puts("Please enter the ANSI file for view (empty to exit):");
  *argv[1]=0;                       /* Prepare to use the argument variable. */
  gets(argv[1]);                                       /* Get the file name. */
  if(*argv[1]==0)return;                  /* If no file name, return to DOS. */
 }
 ansifile=fopen(argv[1],"rt");              /* Opening the file for reading. */
 if(ansifile==NULL)                         /* Check for error opening file. */
 {
  puts("Cannot open input file.");                 /* Put the error message. */
  return;                                                  /* Return to DOS. */
 }
			  /* Reading and parsing the symbols to end of file. */
 while((ansicharster=getc(ansifile))!=0xff)ansi(ansicharster);
 fclose(ansifile);                                        /* Close the file. */
}
