// fed.b                          1430                         5/29/00

// A port of "kaoed.b" for "b" to the "flat real" (non-extended) mode.
// the only major change will be to assign memory for the "text buffer".

#lib fasmlib;

char Alert = 0x35;
char *endptr;
char *fptr;
char *old_top;
char *start;
char *strptr;
char *texpt[6001];
char cha;
char csave;
char err0[] = {"Numeric value required!"}:
char err1[] = {"Search string not found!"}:
char err2[] = {"Error reading file!"}:
char err3[] = {"Cannot allocate memory!"}:
char Hilite = 0x6A;
char instring[50];
char numstring[50];
char filename[] = {"fed.sav"};
char getprompt[] = {"Enter search string: "};
char oldch;
char repprompt[] = {"Enter replacement string: "};
char repstring[50];
char lintext[] = {"Line      of"};
char Norm = 0x1E;
char numprompt[] = {"Enter line number: "};
int addbytes = 480000;        // memory to add for buffer
int botline = 24;             // bottom line of screen display
int count;
int delta;
int foundfirst;
int foundit;
int highval;
int input;
int k;
int l;
int line;
int linecount;
int maxlines = 6000;
int nofile;
int number;
int oldbot;                   // "return" values for failed search
int oldline;
int oldtop;
int realbase;                 // "non-segmented" base of available memory
int replace;
int result;
int scrndelt;                 // "botline" - "topline" for a full screen
int scrnrow;
int topline = 1;              // top line of screen display
int *wptr;

void clean_end(void);         // get rid of <cr><lf>
void clear_end(void);         // clear space for line number
void clear_line(int linum);   // clear line "linum" on screen
void clear_text_buffer(void); // clear text buffer
int confirm(void);            // confirm replacement
void delete_char(void);       // delete character at cursor
void delete_line(int op);     // clear/delete current line
void delete_string(char *str); // delete string "str"
void do_tab(void);            // simulate "tab" (five spaces)
void edit_line(void);         // main line-editing function
void find_left(void);         // find word to left
void find_right(void);        // find word to right
void find_string(void);       // search for "instring"
void get_input(void);         // get input from keyboard
void get_number(void);        // get number from keyboard
void get_string(char *prompt, char *xptr); // get input string
void goto_bottom(void);       // go to end of file
void goto_line(void);         // go to line "number"
void init_pointers(void);     // initialise text pointers
void insert_char(char inch);  // insert character at cursor
void insert_line(void);       // insert blank line
void insert_string(void);     // insert replacement string
void line_down(void);         // go to next line
void line_init(void);         // initialise "line" variables (no display)
void line_up(void);           // go to previous line
void move_left(void);         // move cursor left
void move_right(void);        // move cursor right
void new_screen(int dir);     // up or down one screen
void read_file(int file);     // read text file
void save_file(void);         // save text to "fed.sav"
void screen_init(void);       // display current screen
void show_char_att(char att); // show character with attribute
void show_error(int errnum);  // display error message "errnum"
void show_head(void);         // display top line
void show_help(void);         // display help screen
void show_line(void);         // display text line
void show_linum(void);        // show current line number
void sline_init(void);        // initialise variables for "sline"

void main(int argc, char *argv[])
     {
     get_mode();              // get video mode
     if(mode == 7)            // assume monochrome display
          {
          Alert = 15;
          Hilite = 112;
          Norm = 7;
          attrib = Norm;
          }
     
     _asm mov  eax,stacktop
     _asm add  eax,4
     _asm mov  [membase],eax
     _asm xor  ebx,ebx
     _asm mov  bx,cs
     _asm shl  ebx,4
     _asm add  eax,ebx
     _asm mov  [realbase],eax
     
     go_flat();               // switch  to "flat real mode"
     
     memsize = 640 * 1024;    // top of conventional memory
     memsize = memsize - realbase; // calculate memory available

     if(memsize >= addbytes)
          {
          buffsize = addbytes;
          }
     else                     // set "maxlines" and get even number of lines
          {
          maxlines = memsize / 80;
          buffsize = maxlines * 80;
          }
          
//     printf("\n\n\t%ld lines of text memory allocated.\n\n", maxlines);
//     getkey();

     init_pointers();         // initialise text pointers
     blockcur();              // display block cursor
     clear();
     clear_text_buffer();

     get_rows();
     if(rowcount != 25)
          {
          botline = rowcount - 1;
          }
     scrndelt = rowcount - 2;     

     if(argc > 1)            // if filename entered
          {
          fptr = argv[1];
          handle = fopen(fptr, 0);

          if(ercode)
               {
               printf("\n\n\tError opening %s!\n\n", fptr);
               exit(1);
               }
     
          read_file(handle);  // read text file
          
          if(ercode)
               {
               show_error(2);
               exit(1);
               }          
                    
          fclose(handle);
          }
     else
          {
          nofile = 1;         // show no file loaded
          line = 1;
          linecount = 1;
          topline = 1;
          botline = 1;
          }     
     
     screen_init();           // display current screen

     show_head();             // display top line

     line = topline;
     show_linum();            // show current line number     
     line = 1;
     scrnrow = 1;
     sline_init();
     
     edit_line();
     
     attrib = 7;
    
     clear();
     }
     
void clean_end(void)          // get rid of <cr><lf>
     {
     char *cptr;
     char *limit;
     char tchar;
     char *tptr;
     int test;
     
     tptr = texpt[n] + 79;
     limit = texpt[n] - 1;
     test = 0;
     
     for(cptr = tptr; cptr > limit; cptr--)
          {
          tchar = *cptr;      // get a byte to test
          if(tchar < 32)      // "control" character
               {
               *cptr = 0;     // replace it
               }
          else
               {
               test = 1;      // escape flag
               }
          if(test) break;
          }          
     }          

void clear_end(void)          // clear space for line number
     {
     putcur(59, 0);
     
     _asm mov  ax,0x0920
     _asm mov  bh,0
     _asm mov  bl,[Hilite]
     _asm mov  cx,20
     _asm int  0x10
     }

void clear_line(int linum)    // clear line "linum" on screen
     {
     char lin;
     
     lin = _linum;
     putcur(0, lin);
     
     _asm mov  ax,0x0920
     _asm mov  bh,0
     _asm mov  bl,[attrib]
     _asm mov  cx,80
     _asm int  0x10
     }          

void clear_text_buffer(void)  // clear text buffer
     {
     _asm mov  ebx,[buffsize]
     _asm add  ebx,[membase]
     _asm mov  edx,[membase]
     _asm xor  eax,eax     
     _asm loop1: cmp edx,ebx
     _asm je   ctdone
     _asm mov  [edx],eax
     _asm add  edx,4
     _asm jmp  loop1
     _asm ctdone: nop
     }

int confirm(void)             // confirm replacement
     {
     char cval;
     char *oldptr;
     
     oldptr = ptr;            // save character pointer
     
     attrib = Alert;
     clear_line(0);
     
     putcur(5, 0);
     cprintf("Replace? ");

     getkey();
     show_char();             // echo input
     cval = chval;            // save value
          
     attrib = Hilite;
     clear_line(0);
     sptr = &tail;
     putcur(0, 0);
     show_text(sptr);
     attrib = Norm;
     
     show_linum();
     scrnrow = line - topline;
     scrnrow++;
     sline_init();
     ptr = oldptr;            // restore character pointer     
     
     if(cval == 'y')
          {
          return(1);
          }
     if(cval == 'Y')
          {
          return(1);
          }       
     return(0);        
     }          

void delete_char(void)        // delete character at cursor
     {
     dptr = ptr;
     sptr = ptr + 1;
     
     delta = endptr - sptr;

     while(delta)
          {
          *dptr = *sptr; // shift left
          dptr++;
          sptr++;
          delta = endptr - sptr;
          }     
          
     endptr--;
     *endptr = 0;
     csave = col;
     col = 0;
     row = line - topline;
     row++;
     putcur(col, row);
     for(j = 0; j < 80; j++) 
          {
          chval = 32;
          show_char();
          }
     
     show_line();
     col = csave;
     row = line - topline;
     row++;
     putcur(col, row);
     }

void delete_line(int op)      // clear/delete current line
     {
     ptr = start;
     col = 0;
     row = line - topline;
     row++;
     putcur(col, row);
     
     for(j = 0; j < 80; j++)
          {
          chval = 32;
          show_char();
          *ptr = 0;
          ptr++;
          }
          
     if(_op)
          {
          for(j = line; j < linecount; j++)
               {
               dptr = texpt[j];
               sptr = dptr + 80;

               for(n = 0; n < 80; n++)
                    {
                    cha = *sptr;
                    if(!cha) break;
                    *dptr = cha;
                    *sptr = 0; // clear source character immediately
                    dptr++;
                    sptr++;
                    }
               }
          linecount--;
          delta = line;            // save line number
          screen_init();
          line = delta;            // restore line number          
          }  
     else
          {
          show_line();
          }          

     col = 0;
     row = line - topline;
     row++;
     putcur(col, row);             
     }

void delete_string(char *str) // delete string "str"
     {
     int cnum;
     int limit;
     
     limit = strlen(_str);
     
     for(cnum = 0; cnum < limit; cnum++)
          {
          ptr--;
          col--;
          delete_char();
          }          
     }          

void do_tab(void)             // simulate "tab" (five spaces)
     {
     if(ptr < endptr)
          {
          for(l = 0; l < 5; l++)
               {
               chr = 32;           // space
               insert_char(chr);
               }
          }
     if(ptr == endptr)
          {
          for(n = 0; n < 5; n++)
               {
               *ptr = 32;          // space
               ptr++;
               endptr++;
               col++;
               putcur(col, row);
               }
          }               
     }     

void edit_line(void)          // main line-editing function
     {
     chr = 0;
     while(1)
          {
          get_input();
          if(chr)
               {
               if(ptr == endptr)
                    {
                    *ptr = chr;
                    chval = chr;
                    show_char();
                    col++;
                    ptr++;
                    endptr++;
                    }
               else
                    {
                    insert_char(chr);
                    }     
               }
          if(input == 0x2D00) 
               {
               break;                   // AltX to exit     
               }

          switch(input)    
               { 
               case 0x3B00:             // F1 - Help
                    show_help();
                    break;
                   
               case 0x4B00:     
                       move_left();     // LeftAro     
                       break;     
          
               case 0x4D00:     
                       move_right();    // RightAro     
                       break;     
          
               case 0x4700:     
                       ptr = start;     // Home     
                       col = 0;     
                       putcur(col, row);     
                       break;     
          
               case 0x4F00:     
                       ptr = endptr;    // End     
                       col = ptr - start;     
                       putcur(col, row);     
                       break;     

               case 0x2C1A:     
                       delete_line(0);    // CtlZ
                       scrnrow = line - topline;
                       scrnrow++;
                       sline_init();     
                       break;     
          
               case 0x2D18:     
                       delete_line(1);    // CtlX
                       scrnrow = line - topline;
                       scrnrow++;
                       sline_init();     
                       break;     

               case 0x5300:     
                       delete_char();   // Del     
                       break;     
          
               case 0x0E08:     
                       ptr--;           // BackSp     
                       col--;     
                       n--;     
                       delete_char();     
                       break;     
               
               case 0x4000:             // F6     
                       find_right();    // find word to right     
                       break;     

               case 0x3F00:             // F5     
                       find_left();     // find word to left     
                       break;     

               case 0x0F09:             // <Tab>     
                       do_tab();        // Simulate Tab (5 spaces)     
                       break;     

               case 0x1C0D:             // <Enter>
                       insert_line();   // insert blank line
                       break;
               
               case 0x5000:             // <DownAro>     
                       line_down();     
                       break;     

               case 0x4800:             // <UpAro>     
                       line_up();     
                       break;     
               
               case 0x4400:             // F10
               case 0x1F00:             // AltS (Save File)     
                      attrib = 7;     
                      clear();     
                      save_file();     
                      break;
               
               case 0x5100:             // PageDown     
                      new_screen(1);    // down one screen     
                      break;     

               case 0x4900:             // PageUp     
                      new_screen(0);    // up one screen     
                      break;     

               case 0x3C00:             // F2 (find string)     
                      replace = 0;
                      get_string(getprompt, instring); // get search string
                      find_string();     
                      break;     
                      
               case 0x3D00:             // F3 (find again)
                      line++;           // don't find same string again!
                      find_string(); 
                      if(foundit)
                         {
                         if(replace)
                              {
                              result = confirm(); // confirm replacement
                              if(result)
                                   {
                                   delete_string(instring); // delete "instring"
                                   insert_string(); // insert replacement string
                                   }
                              }
                         }     
                      break;     
                      
               case 0x6900:             // AltF2 (find / replace string)  
                      replace = 1;   
                      get_string(getprompt, instring); // get search string
                      get_string(repprompt, repstring); // get search string                           
                      find_string();
                      if(foundit)
                         {
                         result = confirm(); // confirm replacement
                         if(result)
                              {
                              delete_string(instring); // delete "instring"
                              insert_string(); // insert replacement string
                              }
                         }
                      break;     

               case 0x1E00:             // AltA (top of file)
                      topline = 1;
                      botline = rowcount - 1;
                      if(botline >= linecount)
                         {
                         botline = linecount;
                         }
                      screen_init();
                      line = topline;
                      show_linum();
                      line = 1;
                      scrnrow = 1;
                      sline_init();
                      break;     
                      
               case 0x2C00:             // AltZ (bottom of file)
                      goto_bottom();    // go to end of file
                      break; 
                      
               case 0x2600:             // AltL (go to line)
                      get_number();
                      if(number)
                         {
                         show_head();         
                         goto_line();
                         }
                      else
                         {     
                         show_head();
                         show_linum();
                         scrnrow = line - topline;
                         scrnrow++;
                         sline_init();
                         }
                      break;                                  
               }     
          }
     }                    

void find_left(void)          // find word to left
     {
     fptr = ptr - 1;
     limit = start - 1;
     
     oldch = 32;              // space
     
     foundit = 0;
     
     while(1)
          {
          chr = *fptr;
          if(chr == 32)       // space
               {
               if(oldch > 32) // graphic character
                    {
                    foundit = 1;
                    fptr++;   // back to start
                    ptr = fptr;
                    col = fptr - start;
                    putcur(col, row);
                    }
               }
          oldch = chr;
          fptr--;
          if(fptr == limit)
               {
               if(oldch > 32) // first character of line is graphic
                    {
                    ptr = start;
                    col = 0;
                    putcur(col, row);
                    }
               foundit = 1;   // "fake" to exit
               }
          if(foundit) break;     
          }
     }          

void find_right(void)         // find word to right
     {
     fptr = ptr;
     limit = endptr + 1;
     
     oldch = 50;              // printing character
     
     foundit = 0;
     
     while(1)
          {
          chr = *fptr;
          if(chr > 32)         // graphic character
               {
               if(oldch == 32) // space
                    {
                    foundit = 1;
                    ptr = fptr;
                    col = fptr - start;
                    putcur(col, row);
                    }
               }
          oldch = chr;
          fptr++;
          if(fptr == limit)
               {
               ptr = fptr - 1;
               col = endptr - start;
               putcur(col, row);
               foundit = 1;   // "fake" to exit
               }
          if(foundit) break;     
          }
     }          

void find_string(void)        // search for "instring"
     {
     char *search;
     int limit;
     
     result = line;           // this may be necessary
     oldline = line;          // save values in case of failure
     oldbot = botline;
     oldtop = topline;
     limit = linecount + 1;
     
     foundit = 0;

     for(line = line; line < limit; line++)
          {
          line_init();

          search = strstr(start, instring)
          if(search) break;
          }
          
     if(!search)
          {
          topline = oldtop;     
          botline = oldbot;     
          screen_init();     
          line = oldline; // restore original line     
          sline_init();     
          show_error(1); 
          show_linum();
          scrnrow = line - topline;     
          scrnrow++;     
          row = scrnrow;
          col = 0;     
          putcur(col, row);                   
          return;     
          }               
     else
          {
          if(line > botline)  // if below current screen
               {
               topline = line;
               botline = topline + scrndelt;
               if(botline > linecount)
                    {
                    botline = linecount;
                    }
               screen_init();
               line = topline;
               line_init();
               }     
          col = search - start; // implied "cast"
          scrnrow = line - topline;     
          scrnrow++;     
          row = scrnrow;     
          putcur(col, row);
               
          length = strlen(instring;
          limit = search + length;
          for(fptr = search; fptr < limit; fptr++)     
               {     
               chval = *fptr;     
               show_char_att(Hilite); // show character highlighted     
               }     
          show_linum();     
          col = limit - start;
          ptr = limit;
          foundit = 1;
          putcur(col, row);     
          return;        // all done     
          }     
     }

void get_input(void)          // get input from keyboard
     {
     highval = 0;

     _asm xor  eax,eax
     _asm mov  ah,0
     _asm int  0x16
     _asm mov  [input],eax
     
     highval = input & 0x7F;
     if(highval > 31)
          {
          chr = highval;       // implied "cast"
          highval = 0;
          }
     else 
          {
          chr = 0;
          }
     }     

void get_number(void)         // get number from keyboard
     {
     attrib = Alert;
     clear_line(0);
     
     get_string(numprompt, numstring);
     
     number = atoi(numstring);
     }

void get_string(char *prompt, char *xptr); // get input string
     {
     attrib = Alert;
     clear_line(0);
     
     sptr = _prompt;
     putcur(5, 0);
     show_text(sptr);

     count = 0;

     for(n = 0; n < 50; n++)
          {
          getkey();
          if(chval < 32) 
               {
               break;
               }
          *_xptr = chval;
          _xptr++;
          count++;
          show_char();
          }
     
     *_xptr = 0;
          
     attrib = Hilite;
     clear_line(0);
     sptr = &tail;
     putcur(0, 0);
     show_text(sptr);
     attrib = Norm;
     
     show_linum();
     scrnrow = line - topline;
     scrnrow++;
     sline_init();
     }     

void goto_bottom(void)        // go to end of file
     {
     int texrows;
     
     botline = linecount;
     texrows = rowcount - 1;  // lines of text on screen
     if(linecount <= texrows)
          {
          topline = 1;
          }
     else
          {
          topline = botline - scrndelt;
          }
     
     screen_init();                      
     line = botline;                 
     show_linum();                 
     scrnrow = line - topline;                 
     scrnrow++;                 
     sline_init();
     ptr = endptr;
     col = ptr - start;     
     putcur(col, row);          
     }                 

void goto_line(void)          // go to line "number"
     {
     if(number <= linecount)  // if line exists
          {
          topline = number;
          botline = topline + scrndelt;
          if(botline >= linecount)
               {
               botline = linecount;
               }
          screen_init();
          scrnrow = 1;
          line = number;
          sline_init();
          show_linum();
          row = 1;
          col = 0;
          putcur(col, row);          
          }
     else
          {
          show_linum();
          putcur(col, row);
          }     
     }     

void init_pointers(void)      // initialise text pointers
     {
     int j;
     int limit;
     
     j = 1;
     limit = maxlines + 1;
     
     texpt[j] = membase;
     
     for(n = 2; n < limit; n++)
          {
          texpt[n] = texpt[j] + 80;
          j++;
          }
     }          

void insert_char(char inch)   // insert character at cursor
     {
     sptr = endptr - 1;
     dptr = endptr;
     endptr++;
     
     delta = sptr - ptr;
     delta++;

     while(delta)
          {
          *dptr = *sptr;      // shift right
          dptr--;
          sptr--;
          delta = sptr - ptr;
          delta++;
          }
     
     *ptr = _inch;
     ptr++;
     col++;
     
     csave = col;             // save current "col"
     
     show_line();             // display "text"
     
     col = csave;             // restore "col"
     
     putcur(col, row);
     }
     
void insert_line(void)        // insert blank line
     {
     int delta;
     int limit;
     int lnum;
     int new;
     int old;
     int saveline;
     
     if(line == linecount)    // at end of file
          {
          linecount++;
          line++;
          botline++;
          if(linecount > scrndelt)
               {
               topline = botline - scrndelt;
               }
          else
               {
               topline = 1;
               }
          saveline = line;
          screen_init();
          line = saveline;
          scrnrow = line - topline;
          scrnrow++;
          show_linum();
          sline_init();
          return;
          }

     limit = linecount + 1;
     
     lnum = line;         // save "line"
     line++;

     limit = linecount + 1;

     saveline = texpt[limit];

     for(new = limit; new > line; new--)
          {
          old = new - 1;
          texpt[new] = texpt[old]; // shift pointers
          }

     texpt[line] = saveline;

     linecount++;

     delta = botline - topline;
     if(delta < scrndelt)
          {
          botline++;
          }

     screen_init();
     line = lnum;             // restore line number
     line++;
     scrnrow = line - topline;
     scrnrow++;
     show_linum();
     sline_init();               
     }     

void insert_string(void)      // insert replacement string
     {
     dptr = ptr;              // save "ptr"
     scrnrow = line - topline;
     scrnrow++;
     sline_init();            // clear "highlighting"
     ptr = dptr;              // restore "ptr"
     strptr = &repstring;     // point to replacement string
     
     for(n = 0; n < count; n++)
          {
          chval = *strptr;
          insert_char(chval);
          strptr++
          }
     delta = ptr - start;
     col = delta;
     putcur(col, row);
     }     
     
void line_down(void)          // go to next line
     {
     int offset;
     
     if(line >= linecount)
          {
          return;
          }

     offset = ptr - start;    // save cursor offset
     
     line++;
     if(line > botline)       // at bottom of screen
          {
          topline++;
          botline++;
          screen_init();
          line = botline;
          }
     


     show_linum();            // show current line number
     scrnrow = line - topline;
     scrnrow++;
     sline_init();            // initialise variables for new line
     
     ptr = start + offset;    // try to move straight down
     
     if(ptr > endptr)
          {
          ptr = endptr;
          }

     offset = ptr - start;    // correct column
     col = offset;            // implied "cast"
     putcur(col, row);
     }          

void line_init(void)          // initialise "line" variables (no display)
     {
     ptr = texpt[line];
     start = ptr;
     strlen(start);
     endptr = start + length; // no effect if "length" is zero
     }

void line_up(void)            // go to previous line
     {
     int offset;
     
     if(line == 1)            // already at beginning of file!
          {
          return;
          }     
     
     offset = ptr - start;    // save cursor offset
     line--;
     result = line;           // save line number

          
     if(line < topline)       // above current screen
          {
          topline--;
          botline--;
          screen_init();
          }
     
     line = result;           // restore line number
     show_linum();            // show current line number
     scrnrow = line - topline;
     scrnrow++;
     sline_init();            // initialise variables for new line
     
     ptr = start + offset;    // try to move straight up
     
     if(ptr > endptr)
          {
          ptr = endptr;
          }

     offset = ptr - start;    // correct column
     col = offset;            // implied "cast"
     putcur(col, row);     
     }          

void move_left(void)          // move cursor left
     {
     if(ptr > start)
          {
          ptr--;
          col--;
          putcur(col, row);
          }
     }     
     
void move_right(void)         // move cursor right
     {
     if(ptr < endptr)
          {
          ptr++;
          col++;
          putcur(col, row);
          }
     }

void new_screen(int dir)      // up or down one screen
     {
     delta = rowcount - 3;    // distance to move
     
     if(_dir)                 // screen down
          {
          if(botline == linecount) // already there!
               {
               return;
               }
          botline = botline + delta;
          if(botline > linecount)
               {
               botline = linecount;
               }
          
          topline = botline - scrndelt;
          screen_init();
          line = topline;
          show_linum();       // show current line number          
          line = topline;
          scrnrow = line - topline;
          scrnrow++;
          sline_init();
          }
     else                     // screen up
          {
          if(topline == 1)    // already there!
               {
               return;
               }          
          botline = botline - delta;
          if(botline <= scrndelt)
               {
               topline = 1;
               botline = topline + scrndelt;
               }
          else
               {
               topline = topline - delta;
               botline = topline + scrndelt;
               }     

          screen_init();
          line = topline;
          show_linum();       // show current line number                    
          line = topline;
          scrnrow = 1;
          sline_init();
          }               
     }                         

void read_file(int file)      // read text file
     {
     char *dest;
     int check;
     int limit;
     
     limit = maxlines + 1;
     
     for(n = 1; n < limit; n++)
          {
          dest = texpt[n];
          check = fgets(dest, 80, _file); // read a line
          if(!check) break;   // end of file
          clean_end();        // get rid of <cr><lf>
          }
     if(n == 1)
          {
          return;
          }

     linecount = n - 1; // don't count null line
     line = 1;
     topline = 1;
     if(botline > linecount) // short file!
          {
          botline = linecount;
          }
     ercode = 0;     
     }               

void save_file(void)          // save text to "fed.sav"
     {
     char test;
     
     for(line = linecount; line > 1; line--)
          {
          line_init();
          if(endptr > start)  // if not blank line
               {
               break;
               }
          else
               {
               linecount--;   // skip blank lines at bottom
               }
          }
          
     if(linecount)
          {
          linecount++;        // be sure we print the last line!               
          fptr = &filename;
          handle = fopen(fptr, 1);
          for(line = 1; line < linecount; line++)
               {
               start = texpt[line];
               fprintf(handle, "%s\n", start);
               }
          fclose(handle);
          }
          
     attrib = 7;
     clear();     
     exit(0);          
     }     

void screen_init(void)        // display current screen
     {
     clear();
     show_head();
     
     delta = botline + 1;
     
     for(line = topline; line < delta; line++)
          {
          scrnrow = line - topline;
          scrnrow++;
          sline_init();
          }
     }          

cvoid show_char_att(char att) // show character with attribute
     {
     _asm mov  ah,0x09
     _asm mov  al,[chval]
     _asm mov  bh,0
     _asm mov  bl,[_att]
     _asm mov  cx,1
     _asm int  0x10
     
     col++;
     putcur(col, row);
     }

void show_error(int errnum)   // display error message "errnum"
     {
     attrib = Alert;
     clear_line(0);
     
     switch(_errnum)
          {
          case 0:
               sptr = &err0;
               putcur(5, 0);
               show_text(sptr);
               break;
               
          case 1:
               sptr = &err1;
               putcur(5, 0);
               show_text(sptr);
               break;
               
          case 2:
               sptr = &err2;
               putcur(5, 0);
               show_text(sptr);
               break;                              

          case 3:
               sptr = &err3;
               putcur(5, 0);
               show_text(sptr);
               break;                              
          }
     getkey(); 
     attrib = Norm;
     show_head();    
     }          

void show_head(void)          // display top line
     {
     attrib = Hilite;
     clear_line(0);
     putcur(0, 0);
     show_text(tail);
     putcur(16, 0);
     show_text("Help: F1");
     attrib = Norm;
     }     

void show_help(void)          // display help screen
     {
     char oldcol;
     int offset;
     int oldline;
     
     attrib = Alert;
     clear();
     nocur();
     
     putcur(8, 6);     
     cprintf("Function            Key            Function            Key");
     putcur(8, 8);                         
     cprintf("Cursor left         LeftArrow    Cursor down         DownArrow");
     putcur(8, 9);
     cprintf("Cursor right        RightArrow   Cursor up           UpArrow");
     putcur(8, 10);
     cprintf("Top of file         AltA         Bottom of file      AltZ");
     putcur(8, 11);
     cprintf("Start of line       Home         End of line         End");
     putcur(8, 12);
     cprintf("Go to line #        AltL");
     putcur(8, 14);                         
     cprintf("Delete character    Delete       Backspace/delete    Backspace");
     putcur(8, 15);
     cprintf("Delete line         CtlX         Delete to end       CtlZ");
     putcur(8, 16);
     cprintf("Find word right     F6           Find word left      F5");
     putcur(8, 17);
     cprintf("Simulate Tab (5 sp) Tab          Insert line         Enter");
     putcur(8, 18);
     cprintf("Page down           PageDown     Page up             PageUp");
     putcur(8, 19);
     cprintf("Find string         F2           Find/replace string AltF2");
     putcur(8, 20);
     cprintf("Find/replace again  F3");
     
     getkey();
     attrib = Norm;
     clear();
     blockcur();
     oldcol = col;
     oldline = line;
     offset = ptr - start;
     screen_init();
     show_head();
     line = oldline;
     show_linum();
     scrnrow = line - topline;
     scrnrow++;
     sline_init();
     ptr = ptr + offset;
     row = scrnrow;
     col = oldcol;
     putcur(col, row);     
     }

void show_line(void)          // display text line
     {
     col = 0;
     row = line - topline;
     row++;
     putcur(col, row);
     
     for(sptr = start; sptr < endptr; sptr++)
          {
          chval = *sptr
          show_char();
          }
     }     

void show_linum(void)         // show current line number
     {
     clear_end();             // clear space for line number
     
     attrib = Hilite;

     sptr = &lintext;
     putcur(59, 0);
     show_text(sptr);  // display text

     putcur(64, 0);
     cprintf("%ld", line);
     
     putcur(72, 0);
     cprintf("%ld", linecount);
     
     attrib = Norm;
     }

void sline_init(void)         // initialise variables for "sline"
     {
     chr = 0;
     highval = 0;
     ptr = texpt[line];
     start = ptr;
     strlen(start);
     endptr = start + length; // no effect if "length" is zero
     scrnrow = line - topline;
     scrnrow++;
     clear_line(scrnrow);
     show_line();
     col = 0;
     row = scrnrow;
     putcur(col, row);
     }
