/* cdoc.c */
/*  Copyright (C) 1989 by Jingbai Wang
	jwang@pittvms.bitnet
	jbw@unix.cis.pitt.edu

	Jingbai Wang
	1921 Letsche St.
	Pittsburgh, Pa 15214
	USA
	(412)-323-2060

   This program is released to public as shareware.
   Any individual and institution can use, modify and distribute
   it freely provided the copyright note and the following box 
   are retained. One exception is that profitable distribution (i.e., charge
   over the cost of materials and ship&handling) should have author's written
   permission.
                             */   

/* **********************************************************************
 *            This program was an auxiliary program for Scribe TEC.mak  *
 *               desgined by myself. It is used to view a               *
 *                  DOC file generated by Scribe TEC.mak                *
 *                                                                      *
 *               @make(TEC)                                             *
 *               @libraryfile(vtdoc)                                    *
 *                                                                      *
 *         Since cdoc can read ASCII files of any format, and the vtdoc *
 *       format is simple that any existing formatter or wordprocessor  *
 *       can create it, I desided to make it a general on-line info     *
 *       system. It can be an ideal system documents, news and bulletin *
 *       notes info system.                                             *
 *                                                                      *
 *       It searches for a document list file first, and then list all  *
 *       the documents. You can use cursor to move highlight bar up or  *
 *       down to select to read an article, or select it by number. The *
 *       document list provides path+filename and description of the    *
 *       document.  The document files can be in any directory as long  *
 *       as the reader has read privilege.                              *
 *                                                                      *
 *       If the document file follows vtdoc format as commented below   *
 *       this comment box and help_menu, cdoc can read it like reading  *
 *       a hard copy book, i.e., you can turn to any page, checking up  *
 *       the Table of Contents, and Index. If the document is not in    *
 *       standard vtdoc format, screen pages are assumed. You can still *
 *	 turn to a specific screen page. String search forward or       *
 *       backward  can be performed, and you can save the document into *
 *       a file that you can dump to a printer. 			*
 *    									*
 *       As of today, this info system is found to be the most powerful.*
 *       On VMS, there is a VTX and on UNIX GnuEMACS which have been    *
 *       used as info systems; but all these can't be compared to this  *
 *       cdoc as an on-line info system.                                *    
 ************************************************************************/

/*

   This program is designed to view a page ASCII document file of 46 lines
   per page maximum, and page-marked by form-feed character. i.e., ^L.
   The first page of the table of contents should contain two characters
   ^T (hat and T) and that of index  ^E (not control E).
   Line length is 77 characters maximum.


   But, this program can also be used to view a regular text file which
   will be cut into 23 lines  pages automatically.

   It is intended to have it adoptable to any systems. It is in my mind
   for VMS, MSDOS/PC-DOS and unix for the time being.
   (DOS part not fully hacked yet, it need large/huge memory model)   
*/


/* ****** The following definitions are site dependent   *****
 *             edit them before installation                 *
 *************************************************************/

  /* define the list file for the doc files */

#if VMS
 /*  On VMS, the logical name is doc$list*/
#define DOCFILE_LIST "usr0:[12162.jbw.doc]docfile.lis"
#else
/* on UNIX and DOS, the environment variable is DOCLIST */
#ifndef DOCFILE_LIST
#define DOCFILE_LIST "/udd/xwang/jbdir/doc/docfile.lis"
#endif
#endif

#include <string.h>
#include <math.h>
#include <stdio.h>

#define FALSE 0
#define INBUFSIZE 1024
int inhandle;

#define CLS fprintf(stderr, "\033[2J")
#define GOTOXY(x,y) fprintf(stderr, "\033[%d;%df",x,y)
#define REVERSE fprintf(stderr, "\033[7m")
#define NORMAL fprintf(stderr, "\033[0m")
#define SAVE_CURSOR fprintf(stderr, "\033[s")
#define RESTORE_CURSOR fprintf(stderr, "\033[u")
#define BLINK fprintf(stderr, "\033[5m")
#define BOLD fprintf(stderr, "\033[1m")
#define UNDER fprintf(stderr, "\033[4m")
#define ERASE fprintf(stderr, "\033[K")
#define BELL fprintf(stderr, "\007")
#define CURSOR_RIGHT fprintf(stderr, "\033[1C")
#define CURSOR_LEFT fprintf(stderr, "\033[1D")


#if unix|ultrix
#include <fcntl.h>
#endif
#if ultrix
#define V7 1
#endif


#if   MSDOS|PCDOS
#include <fcntl.h>
#include <stdlib.h>
#if TURBO
#include <conio.h>
#endif
#endif



#if VMS
#include <stdlib.h>
#include <file.h> 
#include        <stsdef.h>
#include        <ssdef.h>
#include        <descrip.h>
#include        <iodef.h>
#include        <ttdef.h>
#include        <tt2def.h>

#define NIBUF   128                     /* Input buffer size            */
#define NOBUF   1024                    /* MM says bug buffers win!     */
#define EFN     0                       /* Event flag                   */

char    obuf[NOBUF];                    /* Output buffer                */
int     nobuf;                  /* # of bytes in above    */
char    ibuf[NIBUF];                    /* Input buffer          */
int     nibuf;                  /* # of bytes in above  */
int     ibufi;                  /* Read index                   */
int     oldmode[3];                     /* Old TTY mode bits            */
int     newmode[3];                     /* New TTY mode bits            */
short   iochan;                  /* TTY I/O channel             */

#endif

#if VMS|unix|ultrix

/*   ANSI escape, good for mainframe systems vt100 terminals, e.g., VAX*/
#define DEL 127
#define EXT 27
#define EXT1 '['
#define R_ARROW 'C'
#define L_ARROW 'D'
#define D_ARROW 'B'
#define U_ARROW 'A'

#else
 /* MSDOS extended code escape */
#define DEL  8
#define EXT  0  
#define R_ARROW 77
#define L_ARROW 75
#define D_ARROW 80
#define U_ARROW 72
#endif

/* The getch() and getche() functions */

#if VMS|unix /* define getch() for VMS and unix*/

int getch()
{
int chr;
ttopen();
chr= ttgetc();
ttclose();
return(chr);
}

int getche()
{
char inchar;
inchar=getch();
fputc(inchar, stdout);
return((int)inchar);
}

#endif


/***************************************************************************
 *                                                                         *
 *  Give 0.5 megabyte memory to mainframe machines and 0.25 kbytes for PC  *
 *                                                                         *
 ***************************************************************************/

#if VMS|unix
#define MAXPAGES 500
#define MAXLENGTH 512000
unsigned char AllBuffer[MAXLENGTH];

#else
#define MAXPAGES 300000
#define MAXLENGTH 256
unsigned char AllBuffer[MAXLENGTH];

#endif




                 /* Global valuables, not too many*/
unsigned int pagenumber;
long int pageptr[MAXPAGES][2], filelength=0;
char  docfilename[80];
int buffer_length;
int lines=1;
int search_flag= -1;
int tt_status=0;

#define tt_open 1
#define tt_close 0

int the_menu=0;
int docfilenumber=0;
int docfiletaken=0;
#define MAX_ROW 20


int tableofcontents = -1, theindex = -1; 
int initpage, startpage, down_screen, up_screen, thepage;
long int start_byte, end_byte;
char command_line[81], the_phrase[81];

struct LOCACTE {
int flag;
int num;
long int where[100];
};



process_arg() /* for processing command-line */
{

}

main(argc, argv)
int argc;
char *argv[];
{
int len, i, dot_check; 


NORMAL;
GOTOXY(25, 1); ERASE;


  dot_check= -1;

  if (argc>1) {strcpy(the_phrase, argv[1]);
               for (i=0; i<strlen(the_phrase); i++)
               if (the_phrase[i]=='.') {dot_check=1;
                                        strcpy(docfilename, the_phrase);
                                        goto menu1;}
               the_menu= -1;
              }

menu: ;

  if (list_menu()<0)
       {CLS;
       GOTOXY(5, 1); ERASE;REVERSE;
        fprintf(stderr, "\n    DOC file (path and name)>");
         NORMAL;  fprintf(stderr, " ");ERASE;
          if(get_line()<0) goto_quit();
             if (command_line[0]>0) { strcpy(docfilename, command_line);}
                  else goto menu;         
       }

  if (argc>2)  process_arg();

menu1:
          /* use system I/O for input*/
   if ( (inhandle=open(docfilename, O_RDONLY))<0)
      {show_error(" DOC file not found "); goto menu;}
 
     initpage=1;
     down_screen=0; up_screen=1;
     startpage=read_pro();
     start_page();
     control(); 
     fflush(stdin);
     goto menu;

}


read_pro()  /* read in the DOC file and page it*/
{
int  quit_s, lines, flag, nonstandard;
char string[80];
long int i, tmplength;
int Newline;

buffer_length=0;
string[0]=0;
AllBuffer[0]=0;
nonstandard= -1;
Newline=1;

     for (i=0; i<MAXPAGES; i++)
      pageptr[i][1]= -1;

quit_s= 1; 
lines=0; pagenumber=1;
pageptr[0][0]=0;
pageptr[1][0]=0;

open_page();

AllBuffer[0]='@';
filelength=1;

  /* read in the file */
while( (flag=read(inhandle, &AllBuffer[filelength], INBUFSIZE))>0)
  {  
     filelength += flag;
  }


GOTOXY(24,1); ERASE;
GOTOXY(24,32); BLINK; 
fprintf(stderr, "Proceccing ....");
NORMAL;

/* process it */

        tmplength=filelength;

        filelength=0;
        i=1;
        lines=0;


        while (i<tmplength)
         {  
           switch(AllBuffer[i])
           {
            case 12:
                       pageptr[++pagenumber][0]=filelength+1;
                       i++; lines=0; if (AllBuffer[i+1]==10) i++; break;
                     
            case 10: lines ++;
                AllBuffer[filelength]=AllBuffer[i];
                                  filelength++; i++;
                    if (AllBuffer[i]=='^')
                      {
                        switch(AllBuffer[i+1])
                          {
                           case 'E': theindex=pagenumber; i +=2; break;
                           case 'T': tableofcontents=pagenumber;  i +=2; break;
                          }
                       }

                if ((lines==23)&&(pageptr[pagenumber][1]<0)) 
                    {
                      pageptr[pagenumber][1]=filelength;
                      lines = 0;
                    }

                if (lines>23) nonstandard=1;
                break;

            default:

                AllBuffer[filelength]=AllBuffer[i];
                   filelength++; i++;
  
             }
            }


     if (pagenumber>1)
      {

       for (i=0; i<80; i++)
       switch(AllBuffer[i+pageptr[2][0]+5])
        {
        case 10:
        case 32: i=80; break;
        case '0':
        case '1':
        case '2':
        case '3':
        case '4':
        case '5':
        case '6':
        case '7':
        case '8':
        case '9': string[i]=AllBuffer[i+pageptr[2][0]+5];
                  break;
     default: nonstandard=2; break;
        }

      if (nonstandard!=2) {
        quit_s=atoi(string)-1; 
         }

       }


 if((nonstandard>0)&&(tableofcontents<0))
         {show_error("Not standard vtdoc file");BELL;BELL;
          for (i=0; i<MAXPAGES; i++)
          pageptr[i][1]= -1; pagenumber=1;
                                  lines=0;
                                      i=0;
                                 do
                                   {
                                     if(AllBuffer[i++]==10) lines++;

                                      if (lines==23)
                                         {
                                         pageptr[++pagenumber][0]=i;
                                         lines = 0;
                                         }
                                    }
                                  while (i<filelength) ;

                              }



AllBuffer[filelength]='\0';
return(quit_s);

}

help_menu() /* print the help menu */
{
char tmpstr[50];
CLS; GOTOXY(3, 1); REVERSE;
fprintf(stderr,
"                             CDOC Help Menu                                ");
NORMAL;GOTOXY(5, 5);
fprintf(stderr, "Space-bar down-page");
GOTOXY(6, 5);
fprintf(stderr, "Tab       up-page");

GOTOXY(7, 5);
fprintf(stderr, "return    next full-page");

GOTOXY(5, 40);
fprintf(stderr, "N next-page");
GOTOXY(6, 40);
fprintf(stderr, "P previous-page");
GOTOXY(7, 40);
fprintf(stderr, "H help");

GOTOXY(9, 5);
fprintf(stderr, "^H back delete in editing");
GOTOXY(10, 5);
fprintf(stderr, "T table of contents");

GOTOXY(9, 40);
fprintf(stderr, "Q exit CDOC");
GOTOXY(10, 40);
fprintf(stderr, "I Index");

GOTOXY(12, 5);
fprintf(stderr, "F forward search");
GOTOXY(12, 40);
fprintf(stderr, "R reverse search");

GOTOXY(13, 5);
fprintf(stderr, "G goto page (e.g., +10, -5, 100)");
GOTOXY(13, 40);
fprintf(stderr, "! system shell    S save in a file");

GOTOXY(16, 20); REVERSE;
fprintf(stderr, " Current DOC File Information ");
NORMAL;

GOTOXY(18, 1);
fprintf(stderr, "      file length     = %ld bytes\n", filelength);
fprintf(stderr, "      number of pages = %d\n", pagenumber);
fprintf(stderr, "      starting page   = %d\n", startpage);

GOTOXY(23, 10); BOLD;
fprintf(stderr, " Hit <space bar> for more help and any other key to exit this menu ");
NORMAL;

if (getch()!=32) return;


CLS; GOTOXY(3, 1); REVERSE;
fprintf(stderr,
"                        CDOC Advaced User's Help Menu                           ");
NORMAL;GOTOXY(5, 2);
fprintf(stderr, "1. CDOC can view any ASCII text files on ANSI standard \
terminals (e.g., vt1xx)");

GOTOXY(6, 2);
fprintf(stderr, "2. CDOC is written in C for multiple operation systems, e.g., \
VMS, unix, MSDOS");

GOTOXY(7, 2);
fprintf(stderr, "3. CDOC uses the following Scribe TEC.mak vtdoc format as standard:");
GOTOXY(8, 4);
fprintf(stderr, "a. paged with ^L (form-feed)");
GOTOXY(9, 4);
fprintf(stderr, "b. maximum length of a page is 46 lines and that of a line \
 77 characters");

GOTOXY(10, 4);
fprintf(stderr, "c. page numbers are placed at extreme left such as `Page 1'");
GOTOXY(11, 4);
fprintf(stderr, "d. The first page of Table of Contents contains ^T (hat and T)");

GOTOXY(12, 4);
fprintf(stderr, "e. The first page of Index contains ^E (hat and E)");
GOTOXY(13, 4);
fprintf(stderr, "f. default max length of a DOC file is 512 kbyte on mainframe \
and 256 kbyte on PC");

GOTOXY(14, 4);
fprintf(stderr, "g. terminal escape characters allowed");
GOTOXY(15, 2);
fprintf(stderr, "4. The easiest way to produce such files is to use TEC.mak \
Scribe database");

GOTOXY(16, 2);
fprintf(stderr, "5. CDOC can let you view a vtdoc format \
file like reading a book.");

GOTOXY(17, 2);
fprintf(stderr, "6. CDOC has many advanced features like system shell.");

GOTOXY(23, 10); BOLD;
fprintf(stderr, " Hit key to exit help menu ");
NORMAL;

getch();
}


control() /* control the menus */
{

char ch;

   while(1)
    {   ch=getch();
      switch(ch)
       {
         case 32: down_page(); search_flag= -1; break;
#if USG
	case 10:
#endif
         case 13: full_page(); search_flag= -1;  break;
         case 9:  up_page(); search_flag= -1;  break;
         case 'N':
         case 'n': next_page(); search_flag= -1;  break;
         case 'P':
         case 'p': previous_page(); search_flag= -1;  break;
         case 'H':
         case 'h': help_menu(); display_page(); break;
         case 'G':
         case 'g':  goto_page(); search_flag= -1;  break;
         case 'T':
         case 't':  goto_table(); search_flag= -1;  break;
         case 'I':
         case 'i': goto_index(); search_flag= -1;  break;
         case 'f':
         case 'F': forward_search(); break;
         case 'r':
         case 'R': reverse_search(); break;
         case 'Q':
         case 'q': BLINK; show_error(" Wait..."); return; break;
         
#if VMS
         case 25:
#endif
#if unix
         case 4:
#endif
         case 3: goto_quit(); break;
         case '!': get_shell(); 
                 display_page(); break;
	 case 'S':
	 case 's': save_file();
	 	break;
#if !USG
	 case 10: break;
#endif
        default: break; /* show_error("Type H for Help"); BELL;*/
      }

    }

}


next_page()  /* turn to next page*/
{
if ((++thepage)>pagenumber) {BELL;--thepage; return;}
down_screen=0; up_screen=0;
      if (thepage==pagenumber)
        { if (pageptr[thepage][1]<0)
           {start_byte=pageptr[thepage][0];
            end_byte=filelength;
           }
        else
          {
           start_byte = pageptr[thepage][0];
           end_byte = pageptr[thepage][1]-1;
           down_screen=1;
          }
        } 
      else 
        { if (pageptr[thepage][1]<0)
           {start_byte=pageptr[thepage][0];
            end_byte=pageptr[thepage+1][0]-1;
           }
        else
          {
           start_byte = pageptr[thepage][0];
           end_byte = pageptr[thepage][1]-1;
           down_screen=1;
          }
        }

  display_page();

}



full_page() /* display next full page*/
{
if ((++thepage)>pagenumber) {BELL;--thepage; return;}
down_screen=0; up_screen=0;
      if (thepage==pagenumber)
        { 
           start_byte=pageptr[thepage][0];
            end_byte=filelength;
        } 
      else 
        {
           start_byte=pageptr[thepage][0];
           end_byte=pageptr[thepage+1][0]-1;
        }

  display_page();


}


previous_page() /* turn to previous page*/
{
if ((--thepage)<initpage) {BELL; ++thepage; return;}
down_screen=0; up_screen=0;
        if (pageptr[thepage][1]<0)
           {start_byte=pageptr[thepage][0];
            end_byte=pageptr[thepage+1][0]-1;
           }
        else
          {
           start_byte = pageptr[thepage][0];
           end_byte = pageptr[thepage][1]-1;
           down_screen=1;
          }

  display_page();

}


down_page() /* go down page */
{
 if (down_screen==1)
     { if (pageptr[thepage][1]<0) {next_page(); return;}

       if (thepage==pagenumber)
          {  start_byte = pageptr[thepage][1];
           end_byte = filelength;
          }
       else 
          { 
           start_byte=pageptr[thepage][1];
            end_byte=pageptr[thepage+1][0]-1;
          }
       down_screen=0; up_screen=1;

       display_page();

 return;
     }
else next_page();

}


up_page() /* go up page*/
{
 if (up_screen==1)
     {  start_byte = pageptr[thepage][0];
        end_byte=pageptr[thepage][1]-1;
        display_page();
        up_screen=0; down_screen=1;
        return;
     }

if ((--thepage)<initpage) {BELL; ++thepage; return;}
down_screen=0; up_screen=0;
        if (pageptr[thepage][1]<0)
           {start_byte=pageptr[thepage][0];
            end_byte=pageptr[thepage+1][0]-1;
           }
        else
          {
           start_byte = pageptr[thepage][1];
           end_byte = pageptr[thepage+1][0]-1;
           down_screen=0; up_screen=1;
          }

  display_page();

}




start_page() /* the starting up page */
{

thepage=initpage;
if(thepage>pagenumber) thepage=pagenumber;
thepage = thepage-1; fflush(stdin);
next_page();

}

display_page() /* display a page */
{
   int i;
   char tmpch;
  
  CLS; GOTOXY(1,1);

tmpch=AllBuffer[end_byte];
AllBuffer[end_byte]='\0';
fprintf(stderr, "%s", &AllBuffer[start_byte]);
AllBuffer[end_byte]=tmpch;

/* fflush(stdin);*/
GOTOXY(24,1); BOLD;
fprintf(stderr, "    Type H for help");NORMAL; 
}



goto_table() /* goto table of contents */
{
if (tableofcontents>0) {thepage=tableofcontents-1; next_page();}
else {BELL; show_error("No table of contents");}

}

goto_index() /*goto index */
{
if (theindex>0) {thepage=theindex-1; next_page();}
else {BELL; show_error("No index"); }
}

next_line()
{
/* attempt to have line feed mode, no time*/
}

  /* search a string by page */
struct LOCACTE string_search(begin_buffer, end_buffer)
int begin_buffer, end_buffer;
{
char *ptr, thisbuffer[4000],  *startptr, *endptr;
int i, j;
long int  the_length;
struct LOCACTE location;

for (i=0; i<100; i++) location.where[i]= -1;
location.flag= -1;

location.num=0;
the_length=end_buffer-begin_buffer;

   for (j=0; j<the_length;j++)
      if ( (AllBuffer[j+begin_buffer]<91) && (AllBuffer[j+begin_buffer]>64))
          thisbuffer[j]=AllBuffer[j+begin_buffer]+32;
      else   thisbuffer[j]=AllBuffer[j+begin_buffer];

thisbuffer[the_length]=0;

ptr = thisbuffer;
startptr=ptr;
endptr=ptr+the_length;


while ((ptr=(char *)memchr(ptr, the_phrase[0], the_length))!=NULL)
    { if(ptr>=endptr) break;
    if( memcmp(ptr, the_phrase, strlen(the_phrase))==0)
      {
     location.where[location.num++]=begin_buffer+ptr-startptr; location.flag=1;
      }
    ptr++; 
    }
return(location);
}


forward_search() /* forward search for a string*/
{
int  this_page, last_page, j;
struct LOCACTE location;
long begin_buffer, end_buffer;
last_page=0;
GOTOXY(24,1); ERASE; GOTOXY(24,1); REVERSE;
fprintf(stderr, "Forward search:"); NORMAL; fprintf(stderr, " ");
if (the_phrase[0]>0) fprintf(stderr, "[%s]", the_phrase);
get_line();

if (command_line[0]>0) {
   for (j=0; j<strlen(command_line);j++)
      if ( (command_line[j]<91) && (command_line[j]>64))
          the_phrase[j]=command_line[j]+32;
      else  the_phrase[j]=command_line[j];
    the_phrase[strlen(command_line)]=0;
      }
  else { if (the_phrase[0]==0)  {GOTOXY(24,1); ERASE;return;}
        else if (search_flag>0) last_page=1;
       }

search_flag=1;

BLINK; fprintf(stderr, "  Searching ...");NORMAL; 


last_page += thepage;
this_page= last_page;

   while (this_page<pagenumber)
     { 
      begin_buffer=pageptr[last_page][0];       
      end_buffer=pageptr[++this_page][0];
      location=string_search(begin_buffer, end_buffer);
      if (location.flag>0) {display_found(last_page, location); return;}
      last_page=this_page;
     }

      begin_buffer=pageptr[pagenumber][0];       
      end_buffer=filelength;
      location=string_search(begin_buffer, end_buffer);
      if (location.flag>0) {display_found(last_page, location); return;}

show_error("String not found");
}

reverse_search() /* reverse search for a string */
{
int  this_page, last_page, j;
struct LOCACTE location;
long int begin_buffer, end_buffer;

GOTOXY(24,1); ERASE; GOTOXY(24,1); REVERSE;
fprintf(stderr, "Reverse search:"); NORMAL; fprintf(stderr, " ");
if (the_phrase[0]>0) fprintf(stderr, "[%s]", the_phrase);
get_line();

if (command_line[0]>0) 
   {for (j=0; j<strlen(command_line);j++)
      if ( (command_line[j]<91) && (command_line[j]>64))
          the_phrase[j]=command_line[j]+32;
      else  the_phrase[j]=command_line[j];
    the_phrase[strlen(command_line)]=0;
   }
  else {
        if (the_phrase[0]==0)  {GOTOXY(24,1); ERASE;return;}
       }

search_flag=1;

BLINK; fprintf(stderr, "  Searching ...");NORMAL;

last_page=thepage;
this_page=thepage;

   while (this_page>initpage)
     { 
      begin_buffer=pageptr[--this_page][0];
      end_buffer=pageptr[last_page][0];       

      location=string_search(begin_buffer, end_buffer);
      if (location.flag>0) {location.flag=2;
                            display_found(this_page, location); return;}
      last_page=this_page;
     }
 
     begin_buffer=pageptr[initpage][0];       
      end_buffer=pageptr[initpage+1][0];
      location=string_search(begin_buffer, end_buffer);
      if (location.flag>0) {location.flag=2;
                            display_found(this_page, location); return;}

show_error("String not found");

}

display_found(thispage, location) /* display found string in a page */
int thispage;
struct LOCACTE location;
{
int i, len, locate;
char tmpch;
long int place[100], starting_ptr;
len=strlen(the_phrase);

locate=0;

for (i=0; i<100; i++)
   if (location.where[i]>0)
     {place[locate]=location.where[i]; locate++;}

thepage=thispage;

down_screen=0; up_screen=0;


      if (thepage==pagenumber)
        { start_byte=pageptr[thepage][0];
          end_byte=filelength;
        } 
      else 
        { start_byte=pageptr[thepage][0];
          end_byte=pageptr[thepage+1][0];
        }
locate=0;


        CLS; GOTOXY(1,1);

place[location.num]=end_byte;
starting_ptr=start_byte;


           for (i=0; i<location.num;i++)
           { 
tmpch=AllBuffer[place[i]];
AllBuffer[place[i]]=0;
fprintf(stderr, "%s", &AllBuffer[starting_ptr]);
REVERSE;
AllBuffer[place[i]]=tmpch;
tmpch=AllBuffer[place[i]+len];
AllBuffer[place[i]+len]=0;
fprintf(stderr, "%s", &AllBuffer[place[i]]);
NORMAL;
AllBuffer[place[i]+len]=tmpch;
starting_ptr=place[i]+len;

           }

tmpch=AllBuffer[end_byte];
AllBuffer[end_byte]=0;
fprintf(stderr, "%s", &AllBuffer[starting_ptr]);
NORMAL;
AllBuffer[end_byte]=tmpch;


}



goto_page() /* goto a certain page */
{
char tmp_str[80], *tmpstr;
int how, starting, i, tmppage, thispage;
starting=0;

GOTOXY(24,1); ERASE; GOTOXY(24,1); REVERSE;
fprintf(stderr, "Goto page:"); NORMAL; fprintf(stderr, " ");
get_line();

if (command_line[0]==0) {GOTOXY(24,1); ERASE; return;}
  GOTOXY(24,1); ERASE;

/*
while (command_line[starting++]==32) ;
*/

 switch(command_line[0])
  {
   case '+': how=1; starting=1; break;
   case '-': how= -1; starting=1; break;
   default: how=0; starting=0;
  }


tmpstr=command_line;
tmpstr += starting;

tmppage=atoi(tmpstr)-startpage+1;

   switch(how)
  {
   case 1: thispage=thepage+tmppage;
            if (thispage>pagenumber) {BELL; thepage=pagenumber-1;}
            else thepage=thispage-1; 
            next_page(); break;
   case -1: thispage = thepage-tmppage;
            if (thispage<initpage) {BELL; thepage=initpage-1;}
            else thepage=thispage-1; 
            next_page(); break;
   case 0: if( tmppage>pagenumber) {BELL; tmppage=pagenumber;}
           if (tmppage<initpage) {tmppage=initpage;BELL;}
            thepage=tmppage-1; next_page(); break;
  }


}


save_file() /* save the document in a file */
{
char filename[80];
FILE *outfile;
long int j;

GOTOXY(24,1); ERASE; GOTOXY(24,1); REVERSE;
fprintf(stderr, "save in file:"); NORMAL; fprintf(stderr, " ");
get_line();

if (command_line[0]==0) {GOTOXY(24,1); ERASE; return;}
  GOTOXY(24,1); ERASE;

  sscanf(command_line, "%s", filename);

  outfile = fopen(filename, "a");

  j=1;
  while(j<filelength) fputc(AllBuffer[j++], outfile);

  fclose(outfile);

 fprintf(stderr, " ==> document appended to %s", filename);
 
}


goto_quit() /* quit CDOC */
{

CLS;
GOTOXY(23,1);
fprintf(stderr, "<<<<< Thank you for using CDOC >>>>>\n");
GOTOXY(25,1); ERASE;
GOTOXY(24, 1); 
    close(inhandle);
exit(1);

}

show_error(message) /* print error message*/
char *message;
{
int i;
fflush(stdin);
GOTOXY(24,1); ERASE;
GOTOXY(24,3); BOLD; 
fprintf(stderr, "******  %s ******", message); NORMAL;
for (i=1; i<10000; i++);
}


get_line() /* line editor */
{
char ch;
int ch_count;
command_line[0]=0;
ch_count=0;



     while(1)
      { 
	ch = getch();
         switch(ch)
          {
          case 0:
	  case 1:
	  case 2:
	  case 5:
	  case 6: 
	  case 7:
	  case 11:
	  case 12:
	  case 14:
	  case 15:
	  case 16:
	  case 19:
	  case 20:
	  case 21:
	  case 22:
	  case 23:
	  case 24:
#if !USG
	  case 10:
#endif
	  case 26:
          case 27:  break;
          case 8:
          case 127:
	          if (ch_count>0){
                  CURSOR_LEFT; ERASE;
                  command_line[--ch_count]=0;
                  }  break;
	  case 9:
#if USG
	  case 10:
#endif
	  case 13: if (ch_count>0)
		     command_line[ch_count]='\0';
		     return;
#if VMS
         case 25:
#endif
#if unix
         case 4:
#endif

	  case 3: command_line[0]=0; return(-1);
	  default: fprintf(stderr, "%c",ch);command_line[ch_count++]=ch;

	 }
    }

}

open_page() /* the first page */
{
CLS;
GOTOXY(2, 20); BOLD;
fprintf(stderr, "Welcome to CDOC Document Viwer");
NORMAL;

 GOTOXY(4, 1); REVERSE;
fprintf(stderr,
"                             CDOC Help Menu                                ");
NORMAL;GOTOXY(5, 5);
fprintf(stderr, "Space-bar down-page");
GOTOXY(6, 5);
fprintf(stderr, "Tab       up-page");

GOTOXY(7, 5);
fprintf(stderr, "return    next full-page");

GOTOXY(5, 40);
fprintf(stderr, "N next-page");
GOTOXY(6, 40);
fprintf(stderr, "P previous-page");
GOTOXY(7, 40);
fprintf(stderr, "H help");

GOTOXY(9, 5);
fprintf(stderr, "G goto page");
GOTOXY(10, 5);
fprintf(stderr, "T table of contents");

GOTOXY(9, 40);
fprintf(stderr, "Q exit CDOC");
GOTOXY(10, 40);
fprintf(stderr, "I Index");

GOTOXY(12, 5);
fprintf(stderr, "F forward search");
GOTOXY(12, 40);
fprintf(stderr, "R reverse search");
GOTOXY(13, 5);
fprintf(stderr, "^H -- back delete in editing");

GOTOXY(16, 20); REVERSE;
fprintf(stderr, " CDOC Program Information ");
NORMAL;

fprintf(stderr, "\n\n              CDOC program is for viewing document");
fprintf(stderr, "\n              files created by TEC.mak and Scribe");
fprintf(stderr, "\n              using device file. It is created by");
fprintf(stderr, "\n              TEC.mak author Jingbai Wang in C for");
fprintf(stderr, "\n              multi operation systems.");

GOTOXY(24,1); ERASE;
GOTOXY(24,10); BLINK; 
fprintf(stderr, "Loading DOC file: %s", docfilename);

NORMAL;

}



/************ the following functions are for list file processing *****/

list_menu()
{
int the_row, i, the_last_menu, the_last_row;
char ch, string[81];

init_buffer();
if (process_list_file()<0) return(-1);
if (the_menu<0) {list_forward_search();
                 the_menu=docfiletaken%20;
                 }
reset_menu(); 


list_in(docfiletaken);

     while(1)
      {   
         ch=getch();
	 switch(ch)
	 {
	  case EXT:

#if VMS|unix

	     ch=getch(); if (ch!=EXT1) {BELL; break;}
	     ch=getch(); 
#else 
	      ch=getch();
#endif
	     switch(ch)
	     {
	      case L_ARROW:
	      case U_ARROW: 
			   list_out(docfiletaken); 
			   --docfiletaken; 
			   list_in(docfiletaken); break;
	      case R_ARROW:
	      case D_ARROW:
                           list_out(docfiletaken);
			   ++docfiletaken; 
			   list_in(docfiletaken); break;
	     default:fflush(stdin); /* BELL;*/
	     } break;

          case '!': fflush(stdin);
                    get_shell();
                    reset_menu(); break;
          case 'f':
          case 'F': list_forward_search(); reset_menu();break;
          case 'r':
          case 'R':  list_reverse_search(); reset_menu();break;
          case 9:  docfiletaken = (--the_menu)*20+19; 
                  if (docfiletaken<0) {docfiletaken=0; BELL;}
                   reset_menu(); break;
          case 32: docfiletaken = (++the_menu)*20; 
                  if (docfiletaken>docfilenumber) {
                     BELL; docfiletaken=docfilenumber;}
                   reset_menu(); break;
#if USG
	case 10:
#endif
	  case 13: if (accept_file()<0) {reset_menu(); break;} else return(1);
          case 3:
#if VMS
         case 25:
#endif
#if unix
         case 4:
#endif
          case 'q':
          case 'Q':  goto_quit(); break;
          case 's':
          case 'S':  select_doc(); reset_menu(); break;
	  default: fflush(stdin);/* BELL;*/

	 }

      }


}


list_in()
{
int the_row, menu_number, j;
char tmpstr[80];

   if (docfiletaken<0) docfiletaken=docfilenumber;
   if (docfiletaken>docfilenumber) docfiletaken=0;   

   the_row = (int) docfiletaken%20;
   menu_number= (int) docfiletaken/20;
   if (menu_number!=the_menu) {the_menu=menu_number; reset_menu();}

   GOTOXY(3+the_row, 3); ERASE;
   GOTOXY(3+the_row, 3); REVERSE;
      for (j=0; j<80; j++)
       {
       tmpstr[j]=AllBuffer[pageptr[docfiletaken][1]+j];
       if (tmpstr[j]==10)  {tmpstr[j]=0;break;}
       }
       fprintf(stderr, "%d. %s",docfiletaken, tmpstr);
   NORMAL;

}

list_out()
{
int the_row, menu_number, j;
char tmpstr[80];
   the_row = (int) docfiletaken%20;
   GOTOXY(3+the_row, 3); ERASE;
   GOTOXY(3+the_row, 3); NORMAL;
      for (j=0; j<80; j++)
       {
       tmpstr[j]=AllBuffer[pageptr[docfiletaken][1]+j];
       if (tmpstr[j]==10)  {tmpstr[j]=0;break;}
       }
       fprintf(stderr, "%d. %s",docfiletaken, tmpstr);

}

reset_menu()
{
int the_row, i, j;
char tmpstr[80];
CLS;
REVERSE;
GOTOXY(1,3);
fprintf(stderr, " Up-arrow/Down-arrow--move highlight bar "); NORMAL; fprintf(stderr, " ");
REVERSE; fprintf(stderr, " Return--accept "); NORMAL;
fprintf(stderr, " ");
REVERSE; fprintf(stderr, " Q--quit");
NORMAL;
fprintf(stderr, " ");
REVERSE; fprintf(stderr, " !--shell");
NORMAL;


REVERSE;
GOTOXY(24,1);
fprintf(stderr, " Space-bar--next page"); NORMAL; fprintf(stderr, " ");
REVERSE; fprintf(stderr, "Tab--previous page"); NORMAL; fprintf(stderr, " ");
REVERSE; fprintf(stderr, "F,R--forward,reverse search");
 NORMAL; fprintf(stderr, " ");
REVERSE; fprintf(stderr, "S--select ");
NORMAL;

   the_menu= (int)docfiletaken/20;
   the_row = (int) docfiletaken%20;
   NORMAL;
   for(i=the_menu*20; i<the_menu*20+20; i++)
     {
      if (i>docfilenumber) break;
      GOTOXY(3+i-the_menu*20, 3); ERASE;
      GOTOXY(3+i-the_menu*20, 3);
      for (j=0; j<80; j++)
       {
       tmpstr[j]=AllBuffer[pageptr[i][1]+j];
       if (tmpstr[j]==10) {tmpstr[j]=0;break;}
       }
       fprintf(stderr, "%d. %s",i, tmpstr);
     }


   GOTOXY(3+the_row, 3); REVERSE;
      for (j=0; j<80; j++)
       {
       tmpstr[j]=AllBuffer[pageptr[docfiletaken][1]+j];
       if (tmpstr[j]==10)  {tmpstr[j]=0;break;}
       }
       fprintf(stderr, "%d. %s",docfiletaken, tmpstr);
   NORMAL;
 fflush(stdin);
}

accept_file()
{
 long int j;

  if (docfiletaken==0) 
       {
        GOTOXY(24, 1); ERASE;REVERSE;
         fprintf(stderr, "    DOC file (path and name)>");
         NORMAL; fprintf(stderr, " ");
         get_line();
         if (command_line[0]>0) { strcpy(docfilename, command_line);}
                           else return(-1);
      }
   else {
          for (j=0; j<80; j++)
         {
          docfilename[j]=AllBuffer[pageptr[docfiletaken][0]+j];
          if (docfilename[j]==32)  {docfilename[j]=0;break;}
          }
         }
   CLS;
   for (j=0; j<=filelength; j++) AllBuffer[j]=0;
pagenumber=0;
lines=1;
search_flag= -1;
tableofcontents = -1;
theindex = -1;

}


process_list_file() /* process the list file for DOC file list*/
    /* the structure of the list is
      path:file1.doc description
      path:file2.doc description
      path:file3.doc description
     ...
       
      one file one line only
    */
{
int i, j, bytess;
extern char *getenv();
char *doclist;
FILE *infile;

#if VMS
      /* use $define/nolog doc$list path:filename
        to define list file on VMS */
	if ((infile=fopen("doc$list", "r"))==NULL)
	if ((infile=fopen(DOCFILE_LIST, "r"))==NULL) return(-1);
#else

    /* define it in the environment variable */

	if (!(doclist=getenv("DOCLIST")) )
		doclist = DOCFILE_LIST;

		if ((infile=fopen(doclist, "r"))==NULL) return(-1);


#endif

#define Starting 77


strcpy(&AllBuffer[42], " User's Text or DOC file \10");
pagenumber=0; pageptr[0][1]=42;

pageptr[1][0]=Starting;
pagenumber=1;
filelength=Starting;


while( fgets(&AllBuffer[filelength], 256, infile)!=NULL)
  {  
	bytess = strlen(&AllBuffer[filelength]);
   	if (bytess>1) filelength += bytess;
  }


   i=1; j=Starting;

   while (j<filelength)
    { 
       while(AllBuffer[j++]!=32); pageptr[i][1]=j;
       while(AllBuffer[j++]!=10); pageptr[i+1][0]=j;
       pagenumber=i++;
    }


    AllBuffer[filelength] = 0;
 docfilenumber=pagenumber;

fclose(infile);
return(1);
}

init_buffer()
{
long int i;


     for (i=0; i<=filelength; i++)
     AllBuffer[i]=0;

pagenumber=0;
lines=1;
search_flag= -1;
tableofcontents = -1;
theindex = -1;
    
}


list_forward_search() /* forward search in file list for a string*/
{
int  this_page, last_page, j, start_search;
struct LOCACTE location;
long begin_buffer, end_buffer;
last_page=0;
if (the_menu>=0)
  {
   GOTOXY(24,1); ERASE; GOTOXY(24,1); REVERSE;
   fprintf(stderr, "Forward search:"); NORMAL; fprintf(stderr, " ");
   if (the_phrase[0]>0) fprintf(stderr, "[%s]", the_phrase);
   get_line();

   if (command_line[0]>0) {
     for (j=0; j<strlen(command_line);j++)
      if ( (command_line[j]<91) && (command_line[j]>64))
          the_phrase[j]=command_line[j]+32;
      else  the_phrase[j]=command_line[j];
    the_phrase[strlen(command_line)]=0;
      }
    else { if (the_phrase[0]==0)  {GOTOXY(24,1); ERASE;return;}
        else if (search_flag>0) last_page=1;
       }




   BLINK; fprintf(stderr, "  Searching ...");NORMAL; 
  }

search_flag=1;
last_page += docfiletaken;
this_page = last_page;

   while (this_page<docfilenumber)
     { 
      begin_buffer=pageptr[last_page][0];       
      end_buffer=pageptr[++this_page][0];
      location=string_search(begin_buffer, end_buffer);
      if (location.flag>0) {docfiletaken=last_page; return;}
      last_page=this_page;
     }

      begin_buffer=pageptr[docfilenumber][0];       
      end_buffer=filelength;
      location=string_search(begin_buffer, end_buffer);
      if (location.flag>0) {docfiletaken=last_page; return;}

show_error("String not found"); BELL; BELL;
}

list_reverse_search() /* reverse search for a string */
{
int  this_page, last_page, j;
struct LOCACTE location;
long int begin_buffer, end_buffer;

GOTOXY(24,1); ERASE; GOTOXY(24,1); REVERSE;
fprintf(stderr, "Reverse search:"); NORMAL; fprintf(stderr, " ");
if (the_phrase[0]>0) fprintf(stderr, "[%s]", the_phrase);
get_line();

if (command_line[0]>0) 
   {for (j=0; j<strlen(command_line);j++)
      if ( (command_line[j]<91) && (command_line[j]>64))
          the_phrase[j]=command_line[j]+32;
      else  the_phrase[j]=command_line[j];
    the_phrase[strlen(command_line)]=0;
   }
  else {
        if (the_phrase[0]==0)  {GOTOXY(24,1); ERASE;return;}
       }

search_flag=1;

BLINK; fprintf(stderr, "  Searching ...");NORMAL;

last_page=docfiletaken;
this_page=docfiletaken;

   while (this_page>0)
     { 
      begin_buffer=pageptr[--this_page][0];
      end_buffer=pageptr[last_page][0];       

      location=string_search(begin_buffer, end_buffer);
      if (location.flag>0) {docfiletaken=this_page; return;}
      last_page=this_page;
     }
 
     begin_buffer=pageptr[0][0];       
      end_buffer=pageptr[initpage+1][0];
      location=string_search(begin_buffer, end_buffer);
      if (location.flag>0) {docfiletaken=this_page; return;}

show_error("String not found");BELL; BELL;

}



select_doc() /* goto a certain page */
{
char tmp_str[80], *tmpstr;
int how, starting, i, tmppage, thispage;
starting=0;

GOTOXY(24,1); ERASE; GOTOXY(24,1); REVERSE;
fprintf(stderr, "Goto number:"); NORMAL; fprintf(stderr, " ");
get_line();

if (command_line[0]==0) {GOTOXY(24,1); ERASE; return;}
  GOTOXY(24,1); ERASE;

/*
while (command_line[starting++]==32) ;
*/

 switch(command_line[0])
  {
   case '+': how=1; starting=1; break;
   case '-': how= -1; starting=1; break;
   default: how=0; starting=0;
  }


tmpstr=command_line;
tmpstr += starting;

tmppage=atoi(tmpstr);

   switch(how)
  {
   case 1: thispage=docfiletaken+tmppage;
            if (thispage>docfilenumber) {BELL; docfiletaken=docfilenumber;}
            else docfiletaken=thispage; 
            break;
   case -1: thispage = docfiletaken-tmppage;
            if (thispage<0) {BELL; docfiletaken=0;}
            else docfiletaken=thispage; 
            break;
   case 0: if( tmppage>docfilenumber) {BELL; tmppage=docfilenumber;}
           if (docfiletaken<0) {docfiletaken=0;BELL;}
            docfiletaken=tmppage;  break;
  }


}



get_shell()
{

CLS;

#if MSDOS
system("command");
#endif

#if unix|ultrix
GOTOXY(24, 1);
ERASE; fprintf(stderr, "Type ^D to return");
system("csh");
#endif


#if VMS
fprintf(stderr, " Type logout to return\n");
system("spawn");
#endif

}


/* for ultrix define V7 = 1 */

/*
 * The functions in this file negotiate with the operating system for
 * characters, and write characters in a barely buffered fashion on the display.
 * All operating systems.
 */


#if   MSDOS & TURBO
#include <conio.h>
#endif

#if     AMIGA
#define NEW 1006L
#define AMG_MAXBUF      1024L
static long terminal;
static char     scrn_tmp[AMG_MAXBUF+1];
static long     scrn_tmp_p = 0;
#endif

#if     CPM
#include        <bdos.h>
#endif

#if     MSDOS & (LATTICE | MSC | TURBO | AZTEC | MWC86)
union REGS rg;          /* cpu register for use of DOS calls */
int nxtchar = -1;       /* character held from type ahead    */
#endif

#if RAINBOW
#include "rainbow.h"
#endif

#if     USG                     /* System V */
#include        <signal.h>
#include        <termio.h>
#include        <fcntl.h>
int kbdflgs;                    /* saved keyboard fd flags      */
int kbdpoll;                    /* in O_NDELAY mode                     */
int kbdqp;                      /* there is a char in kbdq      */
char kbdq;                      /* char we've already read      */
struct  termio  otermio;        /* original terminal characteristics */
struct  termio  ntermio;        /* charactoristics to use inside */
#endif

#if V7 | BSD
/*
#undef  CTRL
*/
#include        <sgtty.h>        /* for stty/gtty functions */
#include        <signal.h>
struct  sgttyb  ostate;          /* saved tty state */
struct  sgttyb  nstate;          /* values for editor mode */
struct tchars   otchars;        /* Saved terminal special character set */
struct tchars   ntchars = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
                                /* A lot of nothing */
#if BSD
#include <sys/ioctl.h>          /* to get at the typeahead */
extern  int rtfrmshell();       /* return from suspended shell */
#define         TBUFSIZ         128
char tobuf[TBUFSIZ];            /* terminal output buffer */
#endif
#endif

/*
 * This function is called once to set up the terminal device streams.
 * On VMS, it translates TT until it finds the terminal, then assigns
 * a channel to it and sets it raw. On CPM it is a no-op.
 */
ttopen()
{

#if     AMIGA
        char oline[NSTRING];
#if     AZTEC
        extern  Enable_Abort;   /* Turn off ctrl-C interrupt */

        Enable_Abort = 0;       /* for the Manx compiler */
#endif
        strcpy(oline, "RAW:0/0/640/200/");
        strcat(oline, PROGNAME);
        strcat(oline, " ");
        strcat(oline, VERSION);
        strcat(oline, "/Amiga");
        terminal = Open(oline, NEW);
#endif
#if     VMS
        struct  dsc$descriptor  idsc;
        struct  dsc$descriptor  odsc;
        char    oname[40];
        int     iosb[2];
        int     status;
if (tt_status==tt_open) return;
tt_status=tt_open;
        odsc.dsc$a_pointer = "TT";
        odsc.dsc$w_length  = strlen(odsc.dsc$a_pointer);
        odsc.dsc$b_dtype        = DSC$K_DTYPE_T;
        odsc.dsc$b_class        = DSC$K_CLASS_S;
        idsc.dsc$b_dtype        = DSC$K_DTYPE_T;
        idsc.dsc$b_class        = DSC$K_CLASS_S;
        do {
                idsc.dsc$a_pointer = odsc.dsc$a_pointer;
                idsc.dsc$w_length  = odsc.dsc$w_length;
                odsc.dsc$a_pointer = &oname[0];
                odsc.dsc$w_length  = sizeof(oname);
                status = LIB$SYS_TRNLOG(&idsc, &odsc.dsc$w_length, &odsc);
                if (status!=SS$_NORMAL && status!=SS$_NOTRAN)
                        exit(status);
                if (oname[0] == 0x1B) {
                        odsc.dsc$a_pointer += 4;
                        odsc.dsc$w_length  -= 4;
                }
        } while (status == SS$_NORMAL);
        status = SYS$ASSIGN(&odsc, &iochan, 0, 0);
        if (status != SS$_NORMAL)
                exit(status);
        status = SYS$QIOW(EFN, iochan, IO$_SENSEMODE, iosb, 0, 0,
                          oldmode, sizeof(oldmode), 0, 0, 0, 0);
        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
                exit(status);
        newmode[0] = oldmode[0];
        newmode[1] = oldmode[1] | TT$M_NOECHO;
        newmode[1] &= ~(TT$M_TTSYNC|TT$M_HOSTSYNC);
        newmode[2] = oldmode[2] | TT2$M_PASTHRU;
        status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
                          newmode, sizeof(newmode), 0, 0, 0, 0);
        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
                exit(status);
/*---        term.t_nrow = (newmode[1]>>24) - 1;
        term.t_ncol = newmode[0]>>16; */

#endif
#if     CPM
#endif

#if     MSDOS & (HP150 == 0) & LATTICE
        /* kill the ctrl-break interupt */
        rg.h.ah = 0x33;                 /* control-break check dos call */
        rg.h.al = 1;            /* set the current state */
        rg.h.dl = 0;            /* set it OFF */
        intdos(&rg, &rg);       /* go for it! */
#endif

#if     USG
        ioctl(0, TCGETA, &otermio);     /* save old settings */
        ntermio.c_iflag = 0;            /* setup new settings */
        ntermio.c_oflag = 0;
        ntermio.c_cflag = otermio.c_cflag;
        ntermio.c_lflag = 0;
        ntermio.c_line = otermio.c_line;
        ntermio.c_cc[VMIN] = 1;
        ntermio.c_cc[VTIME] = 0;
        ioctl(0, TCSETA, &ntermio);     /* and activate them */
        kbdflgs = fcntl( 0, F_GETFL, 0 );
        kbdpoll = FALSE;
#endif

#if     V7 | BSD
if (tt_status==tt_open) return;
        gtty(0, &ostate);                       /* save old state */
        gtty(0, &nstate);                       /* get base of new state */
        nstate.sg_flags |= RAW;
        nstate.sg_flags &= ~(ECHO|CRMOD);       /* no echo for now... */
        stty(0, &nstate);                       /* set mode */
        ioctl(0, TIOCGETC, &otchars);           /* Save old characters */
        ioctl(0, TIOCSETC, &ntchars);           /* Place new character into K */
tt_status=tt_open;
#if     BSD
        /* provide a smaller terminal output buffer so that
           the type ahead detection works better (more often) */
        setbuffer(stdout, &tobuf[0], TBUFSIZ);
/*---        signal(SIGTSTP,SIG_DFL);         set signals so that we can
        signal(SIGCONT,rtfrmshell);      suspend & restart emacs */
#endif
#endif
        /* on all screens we are not sure of the initial position
           of the cursor                                        */
/*---   ttrow = 999;
        ttcol = 999; */

}

/*
 * This function gets called just before we go back home to the command
 * interpreter. On VMS it puts the terminal back in a reasonable state.
 * Another no-operation on CPM.
 */
ttclose()
{

#if     AMIGA
#if     LATTICE
        amg_flush();
        Close(terminal);
#endif
#if     AZTEC
        amg_flush();
        Enable_Abort = 1;       /* Fix for Manx */
        Close(terminal);
#endif
#endif

#if     VMS
        int     status;
        int     iosb[1];

if (tt_status==tt_close) return;
tt_status=tt_close;

        ttflush();
        status = SYS$QIOW(EFN, iochan, IO$_SETMODE, iosb, 0, 0,
                 oldmode, sizeof(oldmode), 0, 0, 0, 0);
        if (status!=SS$_NORMAL || (iosb[0]&0xFFFF)!=SS$_NORMAL)
                exit(status);
        status = SYS$DASSGN(iochan);
        if (status != SS$_NORMAL)
                exit(status);
#endif
#if     CPM
#endif
#if     MSDOS & (HP150 == 0) & LATTICE
        /* restore the ctrl-break interupt */
        rg.h.ah = 0x33;                 /* control-break check dos call */
        rg.h.al = 1;            /* set the current state */
        rg.h.dl = 1;            /* set it ON */
        intdos(&rg, &rg);       /* go for it! */
#endif

#if     USG
        ioctl(0, TCSETA, &otermio);     /* restore terminal settings */
        fcntl(0, F_SETFL, kbdflgs);
#endif

#if     V7 | BSD
if (tt_status==tt_close) return;
        stty(0, &ostate);
        ioctl(0, TIOCSETC, &otchars);   /* Place old character into K */
tt_status=tt_close;
#endif


}

#if     AMIGA
amg_flush()
{
        if(scrn_tmp_p)
                Write(terminal,scrn_tmp,scrn_tmp_p);
        scrn_tmp_p = 0;
}
#endif

/*
 * Flush terminal buffer. Does real work where the terminal output is buffered
 * up. A no-operation on systems where byte at a time terminal I/O is done.
 */
ttflush()
{
#if     AMIGA
        amg_flush();
#endif
#if     VMS
        int     status;
        int     iosb[2];

        status = SS$_NORMAL;
        if (nobuf != 0) {
                status = SYS$QIOW(EFN, iochan, IO$_WRITELBLK|IO$M_NOFORMAT,
                         iosb, 0, 0, obuf, nobuf, 0, 0, 0, 0);
                if (status == SS$_NORMAL)
                        status = iosb[0] & 0xFFFF;
                nobuf = 0;
        }
        return (status);
#endif

#if     CPM
#endif

#if     MSDOS
#endif

#if     V7 | USG | BSD
        fflush(stdout);
#endif
}

/*
 * Read a character from the terminal, performing no editing and doing no echo
 * at all. More complex in VMS that almost anyplace else, which figures. Very
 * simple on CPM, because the system can do exactly what you want.
 */
ttgetc()
{
#if     AMIGA
        char ch;
        amg_flush();
        Read(terminal, &ch, 1L);
        return(255 & (int)ch);
#endif
#if     VMS
        int     status;
        int     iosb[2];
        int     term[2];

        while (ibufi >= nibuf) {
                ibufi = 0;
                term[0] = 0;
                term[1] = 0;
                status = SYS$QIOW(EFN, iochan, IO$_READLBLK|IO$M_TIMED,
                         iosb, 0, 0, ibuf, NIBUF, 0, term, 0, 0);
                if (status != SS$_NORMAL)
                        exit(status);
                status = iosb[0] & 0xFFFF;
                if (status!=SS$_NORMAL && status!=SS$_TIMEOUT)
                        exit(status);
                nibuf = (iosb[0]>>16) + (iosb[1]>>16);
                if (nibuf == 0) {
                        status = SYS$QIOW(EFN, iochan, IO$_READLBLK,
                                 iosb, 0, 0, ibuf, 1, 0, term, 0, 0);
                        if (status != SS$_NORMAL
                        || (status = (iosb[0]&0xFFFF)) != SS$_NORMAL)
                                exit(status);
                        nibuf = (iosb[0]>>16) + (iosb[1]>>16);
                }
        }
        return (ibuf[ibufi++] & 0xFF);    /* Allow multinational  */
#endif

#if     CPM
        return (biosb(BCONIN, 0, 0));
#endif

#if RAINBOW
        int Ch;

        while ((Ch = Read_Keyboard()) < 0);

        if ((Ch & Function_Key) == 0)
                if (!((Ch & 0xFF) == 015 || (Ch & 0xFF) == 0177))
                        Ch &= 0xFF;

        return Ch;
#endif

#if     MSDOS & MWC86
        return (getcnb());
#endif

#if     MSDOS & (LATTICE | MSC | TURBO | AZTEC)
        int c;          /* character read */

        /* if a char already is ready, return it */
        if (nxtchar >= 0) {
                c = nxtchar;
                nxtchar = -1;
                return(c);
        }

        /* call the dos to get a char */
        rg.h.ah = 7;            /* dos Direct Console Input call */
        intdos(&rg, &rg);
        c = rg.h.al;            /* grab the char */
        return(c & 255);
#endif

#if     V7 | BSD
        return(127 & fgetc(stdin));
#endif

#if     USG
        if( kbdqp )
                kbdqp = FALSE;
        else
        {
                if( kbdpoll && fcntl( 0, F_SETFL, kbdflgs ) < 0 )
                        return FALSE;
                kbdpoll = FALSE;
                while (read(0, &kbdq, 1) != 1)
                        ;
        }
        return ( kbdq & 127 );
#endif
}

/* typahead:    Check to see if any characters are already in the
                keyboard buffer
*/

typahead()

{
#if     MSDOS & (MSC | TURBO)
        if (kbhit() != 0)
                return(TRUE);
        else
                return(FALSE);
#endif

#if     MSDOS & (LATTICE | AZTEC | MWC86)
        int c;          /* character read */
        int flags;      /* cpu flags from dos call */

        if (nxtchar >= 0)
                return(TRUE);

        rg.h.ah = 6;    /* Direct Console I/O call */
        rg.h.dl = 255;  /*         does console input */
#if     LATTICE | AZTEC
        flags = intdos(&rg, &rg);
#else
        intcall(&rg, &rg, 0x21);
        flags = rg.x.flags;
#endif
        c = rg.h.al;    /* grab the character */

        /* no character pending */
        if ((flags & 64) != 0)
                return(FALSE);

        /* save the character and return true */
        nxtchar = c;
        return(TRUE);
#endif

#if     BSD | V7
        int x;  /* holds # of pending chars */

        return((ioctl(0,FIONREAD,&x) < 0) ? 0 : x);
#endif

#if     USG
        if( !kbdqp )
        {
                if( !kbdpoll && fcntl( 0, F_SETFL, kbdflgs | O_NDELAY ) < 0 )
                        return(FALSE);
                kbdqp = (1 == read( 0, &kbdq, 1 ));
        }
        return ( kbdqp );
#endif

#if VMS
    return (ibufi < nibuf);
#endif
}

#if ultrix
memmove(s1,s2,len) char *s1, *s2; unsigned len;
   { unsigned i;
   if(s1 <= s2) for(i=0; i<len; ++i) *s1++ = *s2++;
   else for(s1 += len, s2+= len, i=0; i<len; ++i) *--s1 = *--s2;
   }
#endif

