/*-------------------------------------------------------------------------*/
/*      Program:  echo                                                     */
/*   Programmer:  George Kerber                                            */
/*      Written:  08/26/89                                                 */
/*     Compiler:  Lattice 5.04                                             */
/*-------------------------------------------------------------------------*/

#include <stdio.h>
#include <dos.h>
#include <stdlib.h>
#include <string.h>
#include <exec/types.h>

#define WRITTEN "08/26/89 - 01/01/90"
#define VERSION "v1.08c"

void addchar();            /*  Adds characters to outputstring        */
void addstr();             /*  Adds string to outputstring            */
void helpscreen();         /*  Helpscreen                             */
void main();               /*  Main                                   */
void makeline();           /*  Makes a black line                     */
void mistake();            /*  Handles errors                         */
void putcode();            /*  By Garry Glendown (modified by GK)     */
void setattr();            /*  Switch to set attributes               */
int  verifyopt();          /*  Verifies options for numeric content   */

char node[32] , outputstring[256] = "";
char opts[] = "mudhrpsa" , option , *option1;

void main(int argc, char *argv[])
{ 
int escape_char = '*' ;
char *tempy;
char spacer[80];
char *token;          /*  used for strtok                                  */
int i , c_count , counter = -1 , next , z[2] ;
int kflag = 0, nflag = 0, xflag = 0, xyflag = 0, cflag = 0;

/*----- Sets escape value -------------------------------------------------*/

tempy = getenv("ESCAPE");
if(tempy != NULL) escape_char = *tempy;
   
/*----- Calls helpscreen if argv[1] = ? -----------------------------------*/

stcgfn(node,argv[0]);
if(argc == 2 && argv[1][0] == '?') helpscreen(escape_char);

/*----- Gets options ------------------------------------------------------*/

c_count = 0;
for( next = 1 ; (option1 = argopt(argc,argv,opts,&next,&option)) != NULL ; ) { 
   switch(toupper(option)) {
      case 'A':  token = strtok(option1,",");
                 i = 0;
                 while(token != NULL) {
                 if(strlen(token) > 1) mistake("Invalid -a option");
                    setattr(token[0]);
                    token = strtok(NULL,",");
                    }
                 break;
      case 'X':  xflag++; break;           /*  center line                */
      case 'N':  nflag++; break;          /*  supress newline            */
      case 'K':  kflag++; break;          /*  don't reset attributes     */
      case 'Z':  cflag++; nflag = 1; break;  /*  remove cursor             */
      case 'E':  putcode(1); break;         /*  clear to bottom of screen  */
      case 'C':  putcode(0); break;         /*  clear screen               */
      case 'H':  putcode(2,(verifyopt(option1))); break;  /*   scroll up   */
      case 'R':  putcode(3,(verifyopt(option1))); break;  /*   scroll down */
      case 'U':  putcode(4,(verifyopt(option1))); break;  /*   move up     */
      case 'D':  putcode(5,(verifyopt(option1))); break;  /*   move down   */
      case 'P':  token = strtok(option1,",");
                 i = 0;
                 while(token != NULL) {
                    z[i] = verifyopt(token);
                    if(++i > 2) mistake("Excess Options for -p");
                    token = strtok(NULL,",");
                    }
                 if(i != 2) mistake("Missing Option for -p");
                 if(z[1] > 23) mistake("Lines > 23");
                 if(z[0] > 77) mistake("Character Position > 77");
                 if(z[0] != 0) xyflag = 1;
                 putcode(6,z[0],z[1]);
                 break;
     case 'M':   xyflag = 1;
                 i = verifyopt(option1);
                 if(!i || i > 69) mistake("Entry must be 1 - 69");
                 for( ; i > 0 ;strcat(spacer," "), i--) ;
                 break;
      default:   mistake("Invalid Option"); break;
      }
   }


/*  -----  More error checking  -------------------------------------------*/

if(argc > (next + 1)) {
   if(stricmp(argv[next + 1],"NOLINE"))
      mistake("Final option can only be NOLINE");
   if(argc > (next + 2)) mistake("Invalid Option Count");
   }

/*----- Checks input string for escape characters -------------------------*/

if(argc != next) {
   while(argv[next][++counter] != (char *)NULL) {
      if(argv[next][counter] == escape_char) {
         if(argv[next][++counter] == escape_char) {
            c_count++;
            addchar(escape_char);
            continue;
            }
         switch(argv[next][counter]) {
            case 'n' :   addchar('\n'); xyflag = 1; break ;  /*  newline   */
            case 't' :   addchar('\t'); break ;              /*  tab       */
            case 'b' :   addchar('\b'); break ;              /*  backspace */
            case 'q' :   addchar('"') ; c_count++ ; break ;  /*  quote "   */
            case '$' :   break;
            case '\\':   addchar('\\'); c_count++ ; break ;  /*  backslash */
            default  :   /*  check for attribute escape options            */
                         setattr(argv[next][counter]); break ;
            }
         }
         else {
         if(xflag) c_count++;
         addchar(argv[next][counter]);
         }
      continue;
      }
   }

/*----- Actually prints outputstring if one was entered -------------------*/

if(xflag && xyflag) mistake("Invalid option combined with -x");
if(xflag) {
   if(c_count > 74) mistake("Input string too long to center");
   c_count = (80 - c_count) / 2;
   for( ; c_count > 0 ;strcat(spacer," "), c_count--) ;
   }

if(cflag) {
   sprintf(node,"[0m[43m \b[0m");
   strcat(outputstring,node);
   }

printf("%s%s",spacer,outputstring);
if(!kflag) printf("[0m");           /*  retains attribute options if -k  */
if(!stricmp(argv[argc - 1],"NOLINE")) nflag = 1; if(!nflag) printf("\n");
exit(0); 

} 

/*-------------------------------------------------------------------------*/

/*  addstr FUNCTION  (copies passed string to outputstring)  */

void addstr(char string1[])
{
strcat(outputstring,string1);
}

/*-------------------------------------------------------------------------*/

/*  ADDCHAR FUNCTION  (copies passed character to outputstring  */

void addchar(int char1)
{
int i;
i = strlen(outputstring);
outputstring[i] = char1;
outputstring[i + 1] = '\0';
}

/*-------------------------------------------------------------------------*/

/*  HELPSCREEN FUNCTION  */

void helpscreen(int escape_char)
{
int i;
i = 0;
putcode(0);
makeline();
printf("\n%6c[33m[1m%s[0m%13cGeorge Kerber%11s%26s[0m\n\n",i,node,i,VERSION,WRITTEN); 
printf("%6cSYNTAX:  [33m%s [-options] [\"string\"] [NOLINE][0m\n\n",i,node);
printf("%22cEscape Character is currently set to \"[1m[33m%c[0m\"\n\n",i,escape_char);
printf("%11c-a n,n...  Text/screen attributes.  (see docs)\n",i);
printf("%11c-c%10cClear the screen.\n",i,i);
printf("%11c-e%10cDelete from cursor to bottom of screen.\n",i,i);
printf("%11c-n%10cSame as NOLINE, supress newline after printing string.\n",i,i);
printf("%11c-k%10cRetain attributes.\n",i,i);
printf("%11c-x%10cCenter string \(Incompatible with -m\)\n",i,i);
printf("%11c-h|r n%6cScroll up(h) or down(r) \"n\" lines.\n",i,i);
printf("%11c-u|d n%6cMove cursor up or down \"n\" lines.\n",i,i);
printf("%11c-m n%8cBegin string at char position \"n\" (0-77).\n",i,i);
printf("%11c-p x,y%6cSet cursor to position x,y.\n",i,i);
printf("%22cwhere x = char position (0-77) & y = line (0-23).",i);
makeline();
printf("\n");
exit(0);
}

/*-------------------------------------------------------------------------*/

/*  MAKELINE FUNCTION  (prints a black line when called)  */

void makeline()
{
printf("\n[1m[32m  ___________________________________________________________________________\n[0m");
}

/*-------------------------------------------------------------------------*/

/*  MISTAKE FUNCTION  (prints a passwd error message, then exits 5)  */

void mistake(char description[])
{
makeline();
fprintf(stderr,"\n\07[0m      ERROR: %s  [33m%s.[0m",node,description);
makeline();
printf("\n");
exit(5);
}

/*-------------------------------------------------------------------------*/

/*  PUTCODE FUNCTION  */

/*  putcode directions

0   putcode(0)                clear screen
1   putcode(1)                clear to end of screen
2   putcode(2,x)              scroll up 'x' lines
3   putcode(3,x)              scroll down 'x' lines
4   putcode(4,x)              move cursor up 'x' lines
5   putcode(5,x)              move cursor down 'x' lines
6   putcode(6,x,y)            position cursor, x = char # and y = line #

*/


UBYTE code[][9]={
	{12,0},				/*  0  Clear screen            */
	{0x9b,0x4a,0},			/*  1  Clear to end of screen  */
	{0x9b,1,0x53,0},                /*  2  Scroll up               */
	{0x9b,1,0x54,0},		/*  3  Scroll down             */
	{0x9b,1,0x41,0},                /*  4  Move cursor up          */
	{0x9b,1,0x42,0},		/*  5  Move cursor down        */
	{0x9b,1,';',1,0x48,0},		/*  6  Position cursor x,y     */
	};

void putcode(int n, int a0, int a1)
{
int a[3],g,zz = 0;

if(n == 6) {                  /*  reverse a0 and a1 for normal x & y  */
   g = a0;
   a0 = a1;
   a1 = g;
   }

a[0] = a0 ; a[1] = a1 ; a[2] = -1 ;

if(n != 6) a[1] = -1;
if(n == 0 || n == 1) a[0] = -1;

for(g = 0 ; g < 7 ; g++ ) {
   if(!code[n][g]) {
      g = 10; 
      }
      else {
      if(code[n][g] == 1) { 
         if (a[zz] != -1) printf("%d",a[zz]);
         zz++; 
         }
         else {
         putchar(code[n][g]);
         }
      }   
   }
}

/*-------------------------------------------------------------------------*/

/*  SETATTR FUNCTION  (switch statement to handle escape options)  */

void setattr(int char2)
{

switch(char2) {
   case '0':  addstr("[30m"); break; /* color 0 char    */
   case '1':  addstr("[31m"); break; /* color 1 char    */
   case '2':  addstr("[32m"); break; /* color 2 char    */
   case '3':  addstr("[33m"); break; /* color 3 char    */
   case 'D':
   case '4':  addstr("[0m");  break; /* default attr    */
   case 'B':
   case '5':  addstr("[1m");  break; /* bold char                 [0m  */
   case 'U':
   case '6':  addstr("[4m");  break; /* underline char             [0m */
   case 'I':
   case '7':  addstr("[3m");  break; /* italics char               [0m */
   case ')':  addstr("[40m"); break; /* color 0 bkgnd                    */
   case '!':  addstr("[41m"); break; /* color 1 bkgnd                    */
   case '@':  addstr("[42m"); break; /* color 2 bkgnd                    */
   case '#':  addstr("[43m"); break; /* color 3 bkgnd              [0m */
   default :  mistake("Invalid ATTRIBUTE argument"); break;
   }

}

/*-------------------------------------------------------------------------*/

/*  VERIFYOPT FUNCTION  (verifies numeric value and sets j[passed])  */

int verifyopt(char xxx[], int j_value)
{
int i;
if(!strcmp(xxx,"")) mistake("Requires numeric argument for option");
for(i = strlen(xxx) ; i >= 1 ; i-- ) {
   if(!isdigit(xxx[i - 1])) mistake("Missing, negative or non-numeric entry");
   }
return(atoi(xxx));

}

/*-------------------------------------------------------------------------*\

11/01/89 v1.08b:  Re-compiled with Lattice 5.04

\*-------------------------------------------------------------------------*/
