/* Standard 'C' Includes */
#include <dos.h>
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <alloc.h>
#include <ctype.h>
#include <dos.h>
#include <dir.h>

	/* Some User Defined Includes */
#include "genutil.h"
#include "fileutil.h"
#include "keyasm.h"
#include "keybrd.h"
#include "mouseasm.h"
#include "buttons.h"
#include "util.h"

	/* Program Specific Includes */
#include "dagbutil.h"
#include "scrlbar.h"
#include "listbox.h"
#include "filelist.h"
#include "menu.h"
#include "editbook.h"


	/* The main text edit window */
EDIT_LIST editor (1, 1, 80, 25);

	/* For saving/loading the book text */
DAGBOOK_TYPE dagbook;

	/* Default Path to where text files are... */
char text_path [MAX_STRING_LENGTH + 1] = "";

	/* Save the initial available memory for debugging */
long initial_far_heapsize;

	/* For restoring the initial drive+dir on exit */
int orig_disk;
char orig_dir[MAX_STRING_LENGTH];

	/* Main edit loop counter */
boolean quit = FALSE;

	/* Are we in the 80x50 text mode? */
boolean high_textmode = FALSE;

	/* String Descriptions of Program */
char bookedit_version[] = BOOKEDIT_VERSION;
char bookedit_title[] = "BOOKEDIT v%s - Dave Humphrey\n";


/*========== Is ch an alphanumeric character ==============================*/
boolean edit_isalpha (char ch) {

  if (ch < ' ' || ch > '~')
    return (FALSE);
  else
    return (TRUE);

 }
/*========== End of function edit_isalpha() ===============================*/


/*========== Special String Search Function ===============================*/
int edit_strrchr (char *string, int start) {

	/* Make sure there is something there... */
  if (!string) return (-1);

	/* Find the Next Space in Reverse Direction */
  while (start >= 0) {
    if (string[start] == ' ') break;
    start--;
   }

  return (start);
 }
/*========== End of Function edit_strrchr() ===============================*/


/*========== Class EDIT_TYPE Constructor ==================================*/
void EDIT_TYPE::EDIT_TYPE (void) {
  data[0] = 0;
  next = NULL;
  prev = NULL;
 }
/*========== End of Class EDIT_TYPE Constructor ===========================*/


/*========== Class EDIT_TYPE Destructor ===================================*/
void EDIT_TYPE::~EDIT_TYPE (void) {
  if (next) next->prev = prev;
  if (prev) prev->next = next;
 }
/*========== End of Class EDIT_TYPE Destructor ============================*/


/*========== Destroys the Linked List =====================================*/
void EDIT_TYPE::destroy (void) {
  long i = 0;	/* Safety backup */

	/* Assume this one is the start */
  while (next && i < 100000l) {
    delete next;
    i++;
   }

  if (i >= 100000l)
    write_log_entry ("ERROR: Maximum Linked List Destroy Counter Exceeded (100,000)!");

 }
/*========== End of Procedure EDIT_TYPE::destroy() ========================*/


/*========== Class EDIT_LIST Constructor ==================================*/
void EDIT_LIST::EDIT_LIST (const int x1, const int y1, const int w, const int h) {
  edit_view = edit_head = edit_tail = edit_current = NULL;
  num_lines = view = current_char = current_line = 0;
  edit_filename = NULL;
  file_loaded = FALSE;
  pressed = FALSE;
  start_fixed = FALSE;
  modified = FALSE;
  shift_pressed = FALSE;
  x = x1;
  y = y1;
  width = w;
  height = h;
  start_select_char = start_select_line = -1;
  end_select_char = end_select_line = -1;
  end_clip = &clipboard;

  file_menu.init (x + 2, y, 17, "File", BLACK, LIGHTGRAY, LIGHTGRAY, BLACK);
  edit_menu.init (x + 8, y, 21, "Edit", BLACK, LIGHTGRAY, LIGHTGRAY, BLACK);
  help_menu.init (x + width - 12, y, 9, "Help", BLACK, LIGHTGRAY, LIGHTGRAY, BLACK);

	/* Initialize some menus */
  file_menu.add_menu ("New", editmenu_new);
  file_menu.add_menu ("Load Book  F3", editmenu_loadbook);
  file_menu.add_menu ("Save Book  F2", editmenu_savebook);
  file_menu.add_menu ("-", NULL);
  file_menu.add_menu ("Load Text", editmenu_load);
  file_menu.add_menu ("Save Text", editmenu_save);
  file_menu.add_menu ("-", NULL);
  file_menu.add_menu ("Quit    Alt+Q", editmenu_quit);

  edit_menu.add_menu ("Cut       Ctrl+K", editmenu_cut);
  edit_menu.add_menu ("Copy      Ctrl+C", editmenu_copy);
  edit_menu.add_menu ("Paste  Shift+Ins", editmenu_paste);
  edit_menu.add_menu ("-", NULL);
  edit_menu.add_menu ("Change Title", editmenu_title);
  edit_menu.add_menu ("Change Author", editmenu_author);
  edit_menu.add_menu ("-", NULL);
  edit_menu.add_menu ("Font Fancy  Ctrl+F", editmenu_fontfancy);
  edit_menu.add_menu ("Font Normal Ctrl+N", editmenu_fontnormal);
  edit_menu.add_menu ("Center Line", editmenu_center);
  edit_menu.add_menu ("Page Break", editmenu_endpage);

  help_menu.add_menu ("About", editmenu_help);

  scroll_bar.init(x + width - 1, y + 1, y + 1, height - 2, 0, 0);
 }
/*========== End of Class EDIT_LIST Constructor ===========================*/


/*========== Adds a character to The Current Line =========================*/
void EDIT_LIST::add_char (const char ch) {
  int len, i;

	/* Make sure there is something to add to... */
  if (!edit_current) return;
  len = strlen(edit_current->data);

	/* Simply add to a short string */
  if (len < MAX_EDIT_LENGTH) {
    chradd (edit_current->data, current_char, ch);
    modified = TRUE;
    draw_current_line ();
   }
	/* Add a character to middle of long line? */
  else {
		/* Find the first possible space */
     i = edit_strrchr(edit_current->data, MAX_EDIT_LENGTH);

	/* Found a space */
    if (i >= 0) {
      edit_current->data[i] = 0;

	/* Add to the next line or create a new end? */
      if (edit_current->next) {
	len = strlen(edit_current->data + i + 1) + 1;

		/* Will the string fit in the next line? */
	if (strlen(edit_current->next->data) + len < MAX_EDIT_LENGTH) {
	  memmove (edit_current->next->data + len, edit_current->next->data, strlen(edit_current->next->data) + 1);
	  memcpy (edit_current->next->data, edit_current->data + i + 1, len - 1);
	  edit_current->next->data[len - 1] = ' ';
	 }
	else {	/* Create a new line */
	  edit_current = edit_current->next;
	  add_current_line (edit_current->prev->data + i + 1);
	  edit_current = edit_current->prev;
	 }

       }
      else
	add_tail (edit_current->data + i + 1);

      chradd (edit_current->data, current_char, ch);
     }
    else {	/* Just chop the string */

		/* Add to next line or end? */
      if (edit_current->next) {

		/* Will the string fit in the next line? */
	if (strlen(edit_current->next->data) + 1 < MAX_EDIT_LENGTH) {
	  chradd (edit_current->next->data, 0, edit_current->data[MAX_EDIT_LENGTH - 1]);
	  edit_current->data[MAX_EDIT_LENGTH - 1] = 0;
	 }
	else {	/* Create a new line */
	  edit_current = edit_current->next;
	  add_current_line (edit_current->prev->data + MAX_EDIT_LENGTH - 1);
	  edit_current = edit_current->prev;
	  edit_current->data[MAX_EDIT_LENGTH - 1] = 0;
	 }

       }
      else {
	add_tail (edit_current->data + MAX_EDIT_LENGTH);
	edit_current->data[MAX_EDIT_LENGTH] = 0;
       }

      chradd (edit_current->data, current_char, ch);
     }

    modified = TRUE;
    draw_lines (DRAW_ALL);
   } /* End of if long line */
 }
/*========== End of Procedure EDIT_LIST::add_char() =======================*/


/*========== Adds a Tail to the Clipboard =================================*/
void EDIT_LIST::add_cliptail (const char *string) {

	/* Make sure the list exists */
  if (!end_clip) return;

	/* Move to end if not already at end, just in case */
  while (end_clip->next)
    end_clip = end_clip->next;

	/* Attempt to create a new end */
  if(!(end_clip->next = new EDIT_TYPE))
    bug (MEM_ERR_MSG, "*add_cliptail() - %d", sizeof(EDIT_TYPE));

	/* Setup the pointers */
  end_clip->next->prev = end_clip;
  end_clip = end_clip->next;

	/* Copy the string if any into line */
  if (string) {
    strncpy (end_clip->data, string, MAX_EDIT_LENGTH + 1);
    end_clip->data[MAX_EDIT_LENGTH] = 0;
   }
  else
    end_clip->data[0] = 0;

 }
/*========== End of Procedure EDIT_LIST::add_cliptail() ===================*/


/*========== Adds a New Node at the Current Line ==========================*/
void EDIT_LIST::add_current_line (const char *string) {
  EDIT_TYPE *temp_line;		/* Temp Pointer */

	/* No current line, add to tail, if any */
  if (!edit_current) edit_current = edit_tail;

	/* Does List Exist? */
  if (edit_current) {
    temp_line = create_line (string);

	/* Mix up pointers properly... */
    if (edit_current->prev)
      edit_current->prev->next = temp_line;
    else 	/* Must be start of list */
      edit_head = temp_line;

    temp_line->prev = edit_current->prev;
    temp_line->next = edit_current;
    edit_current->prev = temp_line;
    edit_current = temp_line;
   }
  else {
    init (string);
   }

  modified = TRUE;
 }
/*========== End of Procedure EDIT_LIST::add_current_line() ===============*/


/*========== Adds a String at the Current Location ========================*/
void EDIT_LIST::add_string (const char *string, const boolean draw) {
  char buffer[MAX_EDIT_LENGTH * 2 + 4];
  int len, len1, i;

	/* Make sure there is something to add */
  if (!string || !edit_current || !(len = strlen(string)) || len > MAX_EDIT_LENGTH) return;
  len1 = strlen(edit_current->data);

	/* Will the string fit into the line? */
  if (len + len1 < MAX_EDIT_LENGTH) {
    memmove (edit_current->data + current_char + len, edit_current->data + current_char, len1 - current_char + 1);
    memcpy (edit_current->data + current_char, string, len);
   }
	/* Must create a new line so it will fit */
  else if (edit_current->next) {
    strcpy (buffer, edit_current->data);
    memmove (buffer + current_char + len, buffer + current_char, strlen(buffer) - current_char + 1);
    memcpy (buffer + current_char, string, len);

	 /* Find a space to break it at */
    i = edit_strrchr(buffer, MAX_EDIT_LENGTH);

	/* Will the left over pieces fit into next line? */
    if (i >= 0 && strlen(edit_current->next->data) + strlen(buffer + i) < MAX_EDIT_LENGTH) {
      chrcat (buffer, ' ');
      strcat (buffer, edit_current->next->data);
      buffer[i] = 0;
      strcpy (edit_current->data, buffer);
      strcpy (edit_current->next->data, buffer + i + 1);
     }
	/* Create a new line nicely */
    else if (i >= 0 && strlen(buffer + i) < MAX_EDIT_LENGTH) {
      buffer[i] = 0;
      strcpy (edit_current->data, buffer);
      edit_current = edit_current->next;
      add_current_line (buffer + i + 1);
      edit_current = edit_current->prev;
     }
	/* Chop and add to the next line */
    else if (len1 + strlen(buffer)  < MAX_EDIT_LENGTH*2) {
      chrcat (buffer, ' ');
      strcat (buffer, edit_current->next->data);
      strncpy (edit_current->data, buffer, MAX_EDIT_LENGTH);
      edit_current->data[MAX_EDIT_LENGTH] = 0;
      strcpy (edit_current->next->data, buffer + MAX_EDIT_LENGTH);
     }
	/* Chop it off and create a new line */
    else {
      strncpy (edit_current->data, buffer, MAX_EDIT_LENGTH);
      edit_current->data[MAX_EDIT_LENGTH] = 0;
      edit_current = edit_current->next;
      add_current_line (buffer + MAX_EDIT_LENGTH);
      edit_current = edit_current->prev;
     }
   }
	/* Just add to the tail of list */
  else {
    strcpy (buffer, edit_current->data);
    memmove (buffer + current_char + len, buffer + current_char, strlen(buffer) - current_char + 1);
    memcpy (buffer + current_char, string, len);

	/* Find a space to break it at */
    i = edit_strrchr(buffer, MAX_EDIT_LENGTH);

	/* Found a space... otherwise chop off */
    if (i >= 0 && strlen(buffer + i) < MAX_EDIT_LENGTH) {
      buffer[i] = 0;
      strcpy (edit_current->data, buffer);
      add_tail (buffer + i + 1);
     }
    else {
      strncpy (edit_current->data, buffer, MAX_EDIT_LENGTH);
      edit_current->data[MAX_EDIT_LENGTH] = 0;
      add_tail (buffer + MAX_EDIT_LENGTH);
     }
   }

  movechar_rel(0, draw);
  if (draw) draw_lines (DRAW_ALL);
 }
/*========== End of Procedure EDIT_LIST::add_string() =====================*/


/*========== Adds a New Node at the Tail ==================================*/
void EDIT_LIST::add_tail (const char *string) {

	/* Does the list exist? */
  if (edit_tail) {
    edit_tail->next = create_line (string);
    edit_tail->next->prev = edit_tail;
    edit_tail = edit_tail->next;
   }
  else
    init(string);

  modified = TRUE;
 }
/*========== End of Procedure EDIT_LIST::add_tail() =======================*/


/*========== Adds a Line Break at the Current Character ===================*/
void EDIT_LIST::break_line (const boolean draw) {
  char buffer[MAX_EDIT_LENGTH + 1];

	/* Make sure there is something there */
  if (!edit_current) return;

	/* Character at end of line? */
  if (current_char >= strlen(edit_current->data)) {
    if (edit_current->next) {
      edit_current = edit_current->next;
      add_current_line ();
      edit_current = edit_current->prev;
     }
    else
      add_tail ();

    current_char = 0;
    moveline_rel(1, draw);
    if (draw) draw_lines (DRAW_PREVIOUS);
   }
  else {
    strcpy (buffer, edit_current->data + current_char);
    edit_current->data[current_char] = 0;

    if (edit_current->next) {
      edit_current = edit_current->next;
      add_current_line (buffer);
      edit_current = edit_current->prev;
     }
    else
      add_tail (buffer);

    current_char = 0;
    moveline_rel(1, draw);
    if (draw) draw_lines (DRAW_PREVIOUS);
   }

 }
/*========== End of Procedure EDIT_LIST::break_line() =====================*/


/*========== Special Variation of the clreol() function ===================*/
void EDIT_LIST::clear_eol (void) {
  int x1 = wherex(), i;

  for (i = x1; i < x + width - 1; i++)
    putch (' ');

  gotoxy (x1, wherey());
 }
/*========== End of Procedure clear_eol() =================================*/


/*========== Destroys the Clipboard =======================================*/
void EDIT_LIST::clip_destroy (void) {
  clipboard.destroy();
  clipboard.data[0] = 0;
  end_clip = &clipboard;
 }
/*========== End of Procedure EDIT_LIST::clip_destroy() ===================*/


/*========== Attempts to combine to adjacent lines ========================*/
void EDIT_LIST::combine_lines (const int combine_type) {
  EDIT_TYPE *next_line;
  int i;

	/* Fix the current line depending on the combine type */
  if (!edit_current)
    return;
  else if (combine_type == COMBINE_PREV && edit_current->prev)
    edit_current = edit_current->prev;
  else if (combine_type == COMBINE_PREV)
    return;
  else if (combine_type == COMBINE_NEXT && !edit_current->next)
    return;

	/* Set a shortcut to the next line to be combined */
  next_line = edit_current->next;

	/* Will the combined lines fit in the text array? */
  if (strlen(edit_current->data) + strlen(next_line->data) <= MAX_EDIT_LENGTH) {
    chrcat (edit_current->data, ' ');
    strcat (edit_current->data, next_line->data);
    next_line = edit_current;

	/* Delete one of the combined lines */
    edit_current = edit_current->next;
    delete_node();

    edit_current = next_line;
   }
  else {	/* Must carefully combine them */
    i = edit_strrchr (next_line->data, MAX_EDIT_LENGTH - strlen(edit_current->data));

	/* Found a space... otherwise do nothing */
    if (i >= 0) {
      next_line->data[i] = 0;
      chrcat (edit_current->data, ' ');
      strcat (edit_current->data, next_line->data);
      memccpy (next_line->data, next_line->data + i + 1, 0, strlen(next_line->data + i + 1));
     }
   }

 }
/*========== End of Procedure EDIT_LIST::combine_lines() ==================*/


/*========== Copies any Selected Lines to the Clipboard ===================*/
void EDIT_LIST::copy (void) {
  char buffer[MAX_EDIT_LENGTH + 1];	/* Temp buffer */
  EDIT_TYPE *temp_line;			/* Temp pointer */
  int i;	/* Loop counter */

	/* Make sure there is something to copy from */
  if (start_select_line == -1 || end_select_line == -1 || start_select_char == -1 || end_select_char == -1 ||
      start_select_line > end_select_line || (start_select_line == end_select_line && start_select_char > end_select_char)) return;

	/* Clear the clipboard */
  clip_destroy();

	/* Move to the first selected line */
  temp_line = edit_head;

  for (i = 0; i < start_select_line - 1 && temp_line; i++)
    temp_line = temp_line->next;

  if (!temp_line) return;

	/* Start and end on same line? */
  if (end_select_line == start_select_line) {
    strcpy (clipboard.data, temp_line->data + start_select_char);
    clipboard.data[end_select_char - start_select_char + 1] = 0;
   }
  else {	/* More Complicated Case */

	/* Copy the First Line */
    strcpy (clipboard.data, temp_line->data + start_select_char);

	/* Copy the middle lines */
    temp_line = temp_line->next;
    i = start_select_line;

    while (temp_line && i < end_select_line - 1) {
      add_cliptail (temp_line->data);
      temp_line = temp_line->next;
      i++;
     }

	/* And the end line */
    if (i == end_select_line - 1 && temp_line) {
      strcpy (buffer, temp_line->data);
      buffer[end_select_char + 1] = 0;
      add_cliptail (buffer);
     }
   }

	/* No more selected text? */
//  end_select_line = start_select_line = -1;
//  end_select_char = start_select_char = -1;
//  draw_lines (DRAW_ALL);
 }
/*========== End of Procedure EDIT_LIST::copy() ===========================*/


/*========== Cuts any Selected Lines to the Clipboard =====================*/
void EDIT_LIST::cut (void) {
  EDIT_TYPE *temp_line, *end_line;		/* Temp pointers */
  boolean last_char = FALSE;
  int i;			/* Loop counter */

	/* Make sure there is something to copy from */
  if (start_select_line == -1 || end_select_line == -1 || start_select_char == -1 || end_select_char == -1 ||
      start_select_line > end_select_line || (start_select_line == end_select_line && start_select_char > end_select_char)) return;

	/* Clear the clipboard */
  clip_destroy();

	/* Move to the first selected line */
  temp_line = edit_head;

  for (i = 0; i < start_select_line - 1 && temp_line; i++)
    temp_line = temp_line->next;

  if (!temp_line) return;

	/* Start and end on same line? */
  if (end_select_line == start_select_line) {

		/* Copy text to clipboard */
    strcpy (clipboard.data, temp_line->data + start_select_char);
    clipboard.data[end_select_char - start_select_char + 1] = 0;

		/* Clear text */
    memmove (temp_line->data + start_select_char, temp_line->data + end_select_char + 1, strlen(temp_line->data + end_select_char) + 1);
   }
  else { /* More Complicated Case */

		/* Copy First Line to Clip */
    strcpy (clipboard.data, temp_line->data + start_select_char);
    temp_line->data[start_select_char] = 0;

		/* Find the end selected line */
    end_line = temp_line;

    for (i = start_select_line; i < end_select_line - 1 && end_line && end_line->next; i++)
      end_line = end_line->next;

    if (!end_line || !end_line->next) return;

		/* Now reset pointers for the middle lines */
    if (end_select_line - start_select_line >= 2) {
      clipboard.next = temp_line->next;
      end_clip = end_line;
     }
    else
      clipboard.next = NULL;

		/* Check different conditions */
    if (view > start_select_line - 1 && view < end_select_line - 1) {
      edit_view = temp_line;
      view = start_select_line - 1;
     }
    else if (view >= end_select_line - 1)
      view -= end_select_line - start_select_line - 1;


    if (current_line > start_select_line - 1 && current_line <= end_select_line - 1) {
      current_line = start_select_line;
      current_char = 0;
     }
    else if (current_line > end_select_line) {
      current_line -= end_select_line - start_select_line - 1;
      if ((current_line - view) >= height - 2) current_line = view + height - 3;
     }

    num_lines -= end_select_line - start_select_line - 1;

		/* Reset the rest of the pointers */
    if (clipboard.next) clipboard.next->prev = &clipboard;
    end_line = end_line->next;
    temp_line->next = end_line;
    end_line->prev = temp_line;
    end_clip->next = NULL;

		/* Copy Last Line to Clip */
    add_cliptail (end_line->data);
    if (end_select_char - 1 >= strlen(end_line->data)) last_char = TRUE;
    end_clip->data[end_select_char + 1] = 0;
    memmove (end_line->data, end_line->data + end_select_char + 1, strlen(end_line->data + end_select_char) + 1);

	/* Mix around with the points some more */
    if (start_select_char == 0) {

		/* Various cases */
      if (start_select_line == 1 && edit_head->next) {
	edit_head = edit_head->next;
	delete edit_head->prev;

	if (view == 0)
	  edit_view = edit_head;
	else
	  view--;

	if (num_lines) num_lines--;
	if (current_line) current_line--;
	if (current_line == 0) edit_current = edit_head;
       }
      else if (start_select_line - 1 == view && edit_view->prev) {
	edit_view = edit_view->prev;
	delete edit_view->next;
	view--;
	num_lines--;
	current_line--;
       }
		/* Regular line... */
      else {
	delete temp_line;
	num_lines--;
	if (current_line > start_select_line) current_line--;
	if (view > start_select_line) view--;
       }
     } /* End of if start_select_char == 0 */

    if (last_char) {

      if (start_select_char == 0 && start_select_line == 1 && edit_head->next) {
	edit_head = edit_head->next;
	delete edit_head->prev;

	if (view == 0)
	  edit_view = edit_head;
	else
	  view--;

	if (num_lines) num_lines--;
	if (current_line) current_line--;
	if (current_line == 0) edit_current = edit_head;
       }
      else if (start_select_char == 0 && start_select_line - 1 == view && edit_view->prev) {
	edit_view = edit_view->prev;
	delete edit_view->next;
	view--;
	num_lines--;
	current_line--;
       }

      else if (end_select_line >= num_lines && edit_tail->prev) {
	edit_tail = edit_tail->prev;
	delete edit_tail->next;

	if (view == end_select_line - 1) edit_view = edit_tail;
	if (num_lines) num_lines--;

	if (current_line > num_lines - 1) {
	  edit_current = edit_tail;
	  current_line = num_lines - 1;
	 }
       }
      else if (end_select_line - 1 == view && edit_view->prev) {
	edit_view = edit_view->prev;
	delete edit_view->next;
	view--;
	num_lines--;
	current_line--;

	if (current_line > num_lines - 1) {
	  edit_current = edit_tail;
	  current_line = num_lines - 1;
	 }
       }
      else {
	delete end_line;
	num_lines--;
	if (current_line > end_select_line) current_line--;
	if (view > end_select_line) view--;

	if (current_line > num_lines - 1) {
	  edit_current = edit_tail;
	  current_line = num_lines - 1;
	 }
       }

     } /* end of if last_char */

   }

	/* No more selected text? */
  end_select_line = start_select_line = -1;
  end_select_char = start_select_char = -1;
  modified = TRUE;
  draw_lines (DRAW_ALL);
 }
/*========== End of Procedure EDIT_LIST::cut() ============================*/



/*========== Creates a New EDIT_TYPE node =================================*/
EDIT_TYPE *EDIT_LIST::create_line (const char *string) {
  EDIT_TYPE *temp_ptr;

	/* Attempt to Create a new line */
  if(!(temp_ptr = new EDIT_TYPE))
    bug (MEM_ERR_MSG, "*create_line() - %d", sizeof(EDIT_TYPE));

	/* Copy the string if any into line */
  if (string)
    strncpy (temp_ptr->data, string, MAX_EDIT_LENGTH + 1);
  else
    temp_ptr->data[0] = 0;

	/* Increase the number of lines... */
  num_lines++;
  return (temp_ptr);
 }
/*========== End of Function EDIT_LIST::create_line() =====================*/


/*========== Deletes a character from the current position ================*/
void EDIT_LIST::del_char (const int del_type) {
  int char_pos = 0, len;

	/* Make sure there is something to delete */
  if (!edit_current) return;
  len = strlen (edit_current->data);

	/* Determine what type of delete to do */
  switch (del_type) {
    case DEL_DELETE:
      char_pos = current_char;
      break;
    default:
      char_pos = current_char - 1;
      break;
   }

	/* Regular delete in string */
  if (char_pos < len && char_pos >= 0 && len >= 0) {
    chrdel (edit_current->data, char_pos);

    if (del_type == DEL_BACKSPACE)
      movechar_rel(-1);
    else
      movechar_rel(0);

    draw_current_line();
    modified = TRUE;
   }
	/* Must be a more complicated delete case */
  else if (char_pos < 0) {
    current_char = strlen(edit_current->prev->data);
    combine_lines (COMBINE_PREV);
    moveline_rel (-1);
    draw_lines (DRAW_CURRENT);
    modified = TRUE;
   }
  else {
    combine_lines (COMBINE_NEXT);
    draw_lines (DRAW_CURRENT);
    modified = TRUE;
   }

 }
/*========== End of procedure EDIT_LIST::del_char() =======================*/


/*========== Properly Deletes a Node in the List, list_current ============*/
void EDIT_LIST::delete_node (void) {

	/* Don't delete if nothing there */
  if (!edit_current) return;

	/* Is the current line the start of the display screen? */
  if (edit_current == edit_view) {
    if (edit_current->next)
      edit_view = edit_current->next;
    else {
      edit_view = edit_current->prev;
      if (view > 0) view--;
     }
   }

	/* Is the list the last/first line of the text? */
  if (edit_current == edit_tail) edit_tail = edit_tail->prev;
  if (edit_current == edit_head) edit_head = edit_head->next;

	/* Delete the node */
  if (edit_current->next) {
    edit_current = edit_current->next;
    delete edit_current->prev;
    num_lines--;
    modified = TRUE;
   }
  else if (edit_current->prev) {
    edit_current = edit_current->prev;
    delete edit_current->next;
    num_lines--;
    modified = TRUE;
   }
  else {	/* Only node in list, just delete text */
    if (edit_current->data[0]) modified = TRUE;
    edit_current->data[0] = 0;
    current_char = 0;
   }

 }
/*========== End of Procedure EDIT_LIST::delete_node() ====================*/


/*========== Deletes the Entire List ======================================*/
void EDIT_LIST::destroy (void) {

	/* Delete the list if there is any */
  if (edit_head) {
    edit_head->destroy();
    delete edit_head;
   }

  if (edit_filename) {
    delete edit_filename;
    edit_filename = NULL;
   }

  file_loaded = FALSE;
  shift_pressed = FALSE;
  edit_head = edit_tail = edit_current = edit_view = NULL;
  num_lines = view = current_char = current_line = 0;
  start_select_char = start_select_line = -1;
  end_select_char = end_select_line = -1;
  modified = FALSE;
 }
/*========== End of Procedure EDIT_LIST::destroy() ========================*/


/*========== Redraws Some or All the text in the window ===================*/
void EDIT_LIST::draw_lines (const int draw_type) {
  EDIT_TYPE *temp_line;
  int y1;

  if (!edit_current) return;

	/* Choose the Starting Position */
  switch (draw_type) {
    case DRAW_CURRENT:
      temp_line = edit_current;
      y1 = y + 1 + current_line - view;
      break;
    case DRAW_PREVIOUS:

      if (edit_current->prev) {
	temp_line = edit_current->prev;
	y1 = y + current_line - view;
       }
      else {
	temp_line = edit_current;
	y1 = y + 1 + current_line - view;
       }

      break;
    case DRAW_ALL:
      editor.draw_filename();
      editor.draw_status_line();
    default:
      temp_line = edit_view;
      y1 = y + 1;
      break;
   }

  hide_mouse();
  _setcursortype (_NOCURSOR);

	/* Draw the Lines */
  while (temp_line && y1 < y + height - 1) {
    gotoxy (x + 1, y1);
    parse_edit_line (temp_line->data, y1 - y + view);
    clear_eol();
    temp_line = temp_line->next;
    y1++;
   }

	/* Clear rest of lines on screen */
  while (y1 < y + height - 1) {
    gotoxy (x + 1, y1);
    clear_eol ();
    y1++;
   }

	/* Return to current cursor position */
  GOTO_CURSOR;
  _setcursortype (_NORMALCURSOR);
  show_mouse();
 }
/*========== End of procedure EDIT_LIST::draw_lines() =====================*/


/*========== Draws The Current Edit Line ==================================*/
void EDIT_LIST::draw_current_line (void) {

	/* Make Sure We have somethere there */
  if (!edit_current) return;

  hide_mouse ();
  _setcursortype (_NOCURSOR);
  gotoxy (x + 1, y + 1 + current_line - view);
  parse_edit_line (edit_current->data, current_line);
  clear_eol();

	/* Return to cursor position */
  GOTO_CURSOR;
  _setcursortype (_NORMALCURSOR);
  show_mouse ();
 }
/*========== End of procedure EDIT_LIST::draw_current_line() ==============*/


/*========== Draws the border etc... of the edit Window ===================*/
void EDIT_LIST::draw_edit_window (const char *title) {
  int count;

  hide_mouse();
  textcolor (LIGHTGRAY);
  textbackground (BLACK);
  clrscr();

	/* Draw the Header */
  gotoxy (x, y);
  textcolor (BLACK);
  textbackground (LIGHTGRAY);
  cprintf ("%*s", width, " ");

  file_menu.display();
  edit_menu.display();
  help_menu.display();

  textcolor (BLUE);
  cprintf_centx (y, "%s", title);

  textcolor(LIGHTGRAY);
  textbackground(BLACK);

	/* Print right and left sides */
  for (count = y + 1; count < y + height - 1; count++) {
    gotoxy (x, count);
    cprintf ("%c", VERTICAL);
    gotoxy (x + width - 1, count);
    cprintf ("%c", VERTICAL);
   }

	       /* Print the two bottom corners */
  gotoxy (x + width - 1, y + height - 1);
  cprintf ("%c", BOTRIGHT_CORNER);
  gotoxy (x, y + height - 1);
  cprintf ("%c", BOTLEFT_CORNER);

	      /* Print the bottom line... */
  for (count = x + 1; count < x + width - 1; count++)
    cprintf ("%c", HORIZONTAL);

  scroll_bar.draw();

  show_mouse();
  draw_status_line();
  draw_filename();
 }
/*========== End of procedure EDIT_LIST::draw_edit_window() ===============*/


/*========== Updates the Position Status at the Bottom of the Screen ======*/
void EDIT_LIST::draw_status_line (void) {

  hide_mouse();
   _setcursortype(_NOCURSOR);

  gotoxy (x + 5, y + height - 1);
  cprintf (" %3d:%3d ", current_line + 1, current_char + 1);

  if (modified)
    cprintf ("* ");
  else
    cprintf ("  ");

  _setcursortype(_NORMALCURSOR);
  show_mouse();
  scroll_bar.change_max(num_lines - 1 - scroll_bar.max);
  scroll_bar.change_value (current_line);
  GOTO_CURSOR;
 }
/*========== End of Procedure EDIT_LIST::draw_status_line() ===============*/


/*========== Draws in the Filename At the Bottom of the Screen ============*/
void EDIT_LIST::draw_filename (void) {

  hide_mouse();
   _setcursortype(_NOCURSOR);

  gotoxy (x + 20, y + height - 1);

  if (edit_filename)
    cprintf (" %013s ", edit_filename);
  else
    cprintf (" %013s ", "<none>");

  _setcursortype(_NORMALCURSOR);
  show_mouse();
  GOTO_CURSOR;
 }
/*========== End of Procedure EDIT_LIST::draw_filename() ==================*/


/*========== Returns String Length of All Strings in Edit List ============*/
unsigned long EDIT_LIST::get_editsize (void) {
  EDIT_TYPE *line;
  unsigned long size = 0;

  line = edit_head;

  while (line) {
    size += strlen(line->data) + 1;
    line = line->next;
   }

  return (size);
 }
/*========== End of function EDIT_LIST::get_editsize() ====================*/


/*========== We Will Always Need At Least One Line Allocated Initially ====*/
void EDIT_LIST::init (const char *string) {

	/* If list doesn't exist, create the head */
  if (!edit_head) {
    edit_head = create_line (string);
    edit_tail = edit_current = edit_view = edit_head;
    current_line = current_char = view = 0;
    start_select_char = start_select_line = -1;
    end_select_char = end_select_line = -1;
    pressed = FALSE;
    modified = FALSE;
    shift_pressed = FALSE;
   }

 }
/*========== End of Procedure EDIT_LIST::init() ===========================*/


/*========== Attempts to Move to a New Character ==========================*/
boolean EDIT_LIST::movechar_abs (const int new_char, const boolean draw) {
  int len;

	/* Make sure there is a proper pointer */
  if (!edit_current) return (FALSE);

	/* Is this a normal move? */
  if (new_char >= 0 && new_char <= strlen(edit_current->data)) {
    if (current_char == new_char) return (FALSE);
    current_char = new_char;

	/* Need to update selected text? */
    if (get_shift_state() && shift_pressed)
      select_text (current_char + x + 1, current_line - view + y + 1);

    if (draw) draw_status_line();
    return (TRUE);
   }
	/* Move to the previous line */
  else if (new_char < 0) {

	/* Attempt to move to the line */
    if (moveline_rel (-1)) {
      current_char = strlen(edit_current->data) - new_char - current_char;
      if (current_char < 0) current_char = 0;
      if (draw) draw_status_line();

		/* Need to update selected text? */
      if (get_shift_state() && shift_pressed)
	select_text (current_char + x + 1, current_line - view + y + 1);

      return (TRUE);
     }
   }
  else {
    len = strlen(edit_current->data);

	/* Attempt to move to the line */
    if (moveline_rel (1)) {
      current_char = new_char - len;
      len = strlen(edit_current->data);
      if (current_char > len) current_char = len;
      if (draw) draw_status_line();

		/* Need to update selected text? */
      if (get_shift_state() && shift_pressed)
	select_text (current_char + x + 1, current_line - view + y + 1);

      return (TRUE);
     }
   }

  return (FALSE);
 }
/*========== End of Function EDIT_LIST::movechar_abs() ====================*/


/*========== Moves the Cursor to a Given Line =============================*/
boolean EDIT_LIST::moveline_abs (const int line, const boolean draw) {
  int new_line = line, i;

	/* Make sure the number is a valid one... */
  if (new_line < 0)
    new_line = 0;
  else if (line >= num_lines)
    new_line = num_lines - 1;

  if (new_line == current_line) return (FALSE);
  current_line = new_line;
  edit_current = edit_head;

	/* Move the line pointer */
  for (i = 0; i < current_line && edit_current; i++)
    edit_current = edit_current->next;

  if (!edit_current) edit_current = edit_tail;
  i = strlen(edit_current->data);
  if (current_char > i) current_char = i;

	/* Check the view */
  if (current_line < view) {
    edit_view = edit_current;
    view = current_line;

	/* Need to update selected text? */
    if (get_shift_state() && shift_pressed)
      select_text (current_char + x + 1, current_line - view + y + 1);
    else if (draw)
      draw_lines (DRAW_ALL);
   }
  else if (current_line > view + height - 3) {

    for (i = 0; i < current_line - view - height + 3 && edit_view; i++)
      edit_view = edit_view->next;

    if (!edit_view) {
      edit_view = edit_current;
      view = current_line;
     }

    view = current_line - height + 3;
    moveline_abs (view + height - 3, draw);

	/* Need to update selected text? */
    if (get_shift_state() && shift_pressed)
      select_text (current_char + x + 1, current_line - view + y + 1);
    else if (draw)
      draw_lines (DRAW_ALL);
   }
  else {
    if (get_shift_state() && shift_pressed)
      select_text (current_char + x + 1, current_line - view + y + 1);

    if (draw) draw_status_line();
   }

  return (TRUE);
 }
/*========== End of Function EDIT_LIST::moveline_abs() ====================*/


/*========== Moves the Cursor to a New Position relative to the screen ====*/
void EDIT_LIST::move_cursor (int mx, int my, const boolean draw) {

	/* Click in text window */
  if (mx > x && mx < x + width - 1 && my > y && my < y + height - 1) {

	/* Click on the current line */
    if (my == y + 1 + current_line - view) {

      if (mx - x - 1 > strlen(edit_current->data))
	movechar_abs (strlen(edit_current->data), draw);
      else
	movechar_abs (mx - x - 1, draw);
     }

	/* Click on new line */
    else {
      moveline_abs (my - y - 1 + view, draw);

      if (mx - x - 1 > strlen(edit_current->data))
	movechar_abs (strlen(edit_current->data), draw);
      else
	movechar_abs (mx - x - 1, draw);
     }

   } /* End of click in text window */
 }
/*========== End of Procedure EDIT_LIST::move_cursor() ====================*/


/*========== Parses An Edit Line, Printing in Color? ======================*/
void EDIT_LIST::parse_edit_line(const char *string, const int line) {
  boolean select = FALSE;
  int select_line = SELECT_NONE;
  int orig_text_color, orig_back_color;
  int text_color2, back_color2;
  int text_color4, back_color4;
  int i = 0;

  if (!string) return;
  text_color2 = orig_text_color = get_text_color();
  back_color2 = orig_back_color = get_back_color();

	/* Determine selected status */
  if (line == start_select_line && line == end_select_line)
    select_line = SELECT_BOTH;
  else if (line == start_select_line)
    select_line = SELECT_START;
  else if (line == end_select_line) {
    select_line = SELECT_END;
    select = TRUE;
    textcolor (BLACK);
    textbackground (LIGHTGRAY);
   }
  else if (line > start_select_line && line < end_select_line) {
    select_line = SELECT_MIDDLE;
    select = TRUE;
    textcolor (BLACK);
    textbackground (LIGHTGRAY);
   }

	/* Print to end of line */
  while (string[i] && i < editor.width - 2) {

	/* Determine selected status */
    if (select_line == SELECT_BOTH && !select && i >= start_select_char && i < end_select_char) {
      select = TRUE;
      textcolor (SELECT_TEXT_COLOR);
      textbackground (SELECT_BACK_COLOR);
     }
    else if (select_line == SELECT_START && !select && i >= start_select_char) {
      select = TRUE;
      textcolor (SELECT_TEXT_COLOR);
      textbackground (SELECT_BACK_COLOR);
     }
    else if ((select_line == SELECT_END || select_line == SELECT_BOTH) && select && i > end_select_char) {
      textcolor (LIGHTGRAY);
      textbackground (BLACK);
      select = FALSE;
     }

    if (select)
      cprintf ("%c", string[i]);
    else {

      switch (string[i]) {
	case '}':		/* If Font Selected Char */
	  cprintf ("}");
	  textcolor (text_color2);
	  textbackground (back_color2);
	  break;
	case '{':
	  text_color2 = get_text_color();
	  back_color2 = get_back_color();
	  textcolor (FONT_TEXT_COLOR);
	  textbackground (FONT_BACK_COLOR);
	  cprintf ("{");
	  break;
	case END_PAGE_CHAR:	/* End of Page Section */
	  text_color4 = get_text_color();
	  back_color4 = get_back_color();
	  textcolor (END_PAGE_TEXT_COLOR);
	  textbackground (END_PAGE_BACK_COLOR);
	  cprintf ("~");
	  textcolor (text_color4);
	  textbackground (back_color4);
	  break;
	case CENTER_CHAR:		/* Center Text Section */
	  text_color4 = get_text_color();
	  back_color4 = get_back_color();
	  textcolor (CR_TEXT_COLOR);
	  textbackground (CR_BACK_COLOR);
	  cprintf ("%c", string[i]);
	  textcolor (text_color4);
	  textbackground (back_color4);
	  break;
	case HEX_CHAR:			/* Possible Hex String? */
	  if (isxdigit(string[i + 1]) && isxdigit(string[i + 2])) {
	    text_color4 = get_text_color();
	    back_color4 = get_back_color();
	    textcolor (HEX_TEXT_COLOR);
	    textbackground (HEX_BACK_COLOR);
	    cprintf ("#%c%c", string[i + 1], string[i + 2]);
	    i += 2;
	    textcolor (text_color4);
	    textbackground (back_color4);
	   }
	  else
	    cprintf ("%c", string[i]);

	  break;
	default:			/* Just put a character */
	  cprintf ("%c", string[i]);
	  break;
       } /* End of switch */
     }

    i++;
   } /* End of while loop */

  textcolor (orig_text_color);
  textbackground (orig_back_color);
 }
/*========== End of procedure EDIT_LIST::parse_edit_line() ================*/


/*========== Pastes the Clipboard Contents at the Current Location ========*/
void EDIT_LIST::paste (void) {
  EDIT_TYPE *temp_line;		/* Temp pointer */
  int pre_char = current_char;

	/* Make sure there is something to paste and a place to paste to */
  if (!strlen(clipboard.data) || !edit_current) return;

	/* Only One Line of Text to paste? */
  if (!clipboard.next) {
    add_string (clipboard.data);
   }
	/* More Complicated */
  else {

	/* Break the Line at the current point */
    break_line (FALSE);

	/* Start with the last line in the clipboard and add a new line */
    temp_line = end_clip;

    while (temp_line->prev) {
      add_current_line (temp_line->data);
      temp_line = temp_line->prev;
     }

	/* Add the first line */
    if (edit_current->prev) {
      edit_current = edit_current->prev;
      current_char = pre_char;
      add_string (temp_line->data, FALSE);
      current_line--;
     }
    else
      add_string (temp_line->data, FALSE);

    draw_lines (DRAW_ALL);
   }
 }
/*========== End of Procedure EDIT_LIST::paste() ==========================*/


/*========== Procedure For Selecting Text Lines ===========================*/
void EDIT_LIST::select_text (const int mx, const int my) {
  int i, j;	/* Temp variables */

	/* Is the new screen position valid? */
  if (mx > x && mx < x + width - 1 && my > y && my < y + height - 1) {
    i = mx - x - 1;
    j = my - y + view;

    if (start_fixed && (j < start_select_line || (j == start_select_line && i < start_select_char))) {
      swap (start_select_line, end_select_line);
      swap (start_select_char, end_select_char);
      start_fixed = FALSE;
     }
    else if (!start_fixed && (j > end_select_line || (j == start_select_line && i > end_select_char) || start_fixed)) {
      swap (start_select_line, end_select_line);
      swap (start_select_char, end_select_char);
      start_fixed = TRUE;
     }

    if (start_fixed && (i != end_select_char || j != end_select_line)) {
      if (j > num_lines) j = num_lines;
      end_select_line = j;
      end_select_char = i;
      draw_lines (DRAW_ALL);
     }
    else if (!start_fixed && (i != start_select_char || j != start_select_line)) {
      start_select_line = j;
      start_select_char = i;
      draw_lines (DRAW_ALL);
     }

   }

 }
/*========== End of Procedure EDIT_LIST::select_text() ====================*/


/*========== Main loop for the text editor ================================*/
void EDIT_LIST::text_editor(const char *title) {
  boolean pre_shift = FALSE;
  int mx, my, event, i;
  char ch;

  quit = FALSE;
  _wscroll = 0;

	/* Initialize the list */
  init();

	/* Draw Some Things */
  draw_edit_window (title);
  draw_lines (DRAW_ALL);
  gotoxy (x + 1, y + 1);

  do {

	/* A mouse click somewhere? */
    event = get_mouse_event (LEFT_BUTTON);
    get_mouse_pos();
    mx = MOUSEX;
    my = MOUSEY;

    if ((i = scroll_bar.check (MOUSEX, MOUSEY, event)) != NO_SCROLL) {
      moveline_rel(i);
     }
		/* Check for a click on the 'file menu' */
    else if (file_menu.check (mx, my, event)) {
      GOTO_CURSOR;
      _setcursortype (_NORMALCURSOR);
     }
		/* Check the Edit Menu */
    else if (edit_menu.check (mx, my, event)) {
      GOTO_CURSOR;
      _setcursortype (_NORMALCURSOR);
     }
		/* Check the Help Menu */
    else if (help_menu.check (mx, my, event)) {
      draw_edit_window(title);
      draw_lines (DRAW_ALL);
      GOTO_CURSOR;
      _setcursortype (_NORMALCURSOR);
     }

    else if (event == BUTTON_PRESS) {

      if (mx > x && mx < x + width - 1 && my > y && my < y + height - 1) {
	end_select_char = start_select_char = mx - x - 1;
	end_select_line = start_select_line = my - y + view;
	draw_lines (DRAW_ALL);
	pressed = TRUE;
	move_cursor (mx, my);
       }
     }

	/* For selecting text */
    else if (pressed && event == NO_EVENT && MouseButtonStatus != 0) {
      mx = (MouseX>>2) + 1;
      my = (MouseY>>3) + 1;
      select_text (mx, my);
      move_cursor (mx, my);
      show_mouse();
     }

    else if (event == BUTTON_RELEASE) {
      move_cursor(mx, my);
      pressed = FALSE;
     } /* End of if BUTTON_RELEASE */

	/* Check Keyboard Input */
    GetKey();
    ch = (char) keylast;

	/* ALT-F = File Menu */
    if (get_alt_key(SCAN_F)) {
      file_menu.display_menu();
      gotoxy (current_char + 2, current_line + 2);
      _setcursortype (_NORMALCURSOR);
     }
	/* ALT-E = Edit Menu */
    else if (get_alt_key(SCAN_E)) {
      edit_menu.display_menu();
      gotoxy (current_char + 2, current_line + 2);
      _setcursortype (_NORMALCURSOR);
     }
	/* ALT-Q = Quit */
    else if (get_alt_key(SCAN_Q)) {
      editmenu_quit();
     }
	/* ALT-H/F1 = Help */
    else if ((key_press[SCAN_F1] != 0) || (get_alt_key(SCAN_H))) {
      editmenu_help (NULL);
      draw_edit_window (title);	/* Redraw screen */
      draw_lines (DRAW_ALL);
     }
	/* For Debugging... */
    else if (get_alt_key (SCAN_D)) {
      delay (KEY_DELAY);
     }
	/* F2, save book */
    else if (key_press[SCAN_F2] != 0) {
      editmenu_savebook(NULL);
      gotoxy (current_char + 2, current_line + 2);
      _setcursortype (_NORMALCURSOR);
     }
	/* F3, Load Book */
    else if (key_press[SCAN_F3] != 0) {
      editmenu_loadbook(NULL);
      gotoxy (current_char + 2, current_line + 2);
      _setcursortype (_NORMALCURSOR);
     }
	/* Ctrl+C, Copy */
    else if (get_ctrl_key(SCAN_C)) {
      editmenu_copy();
      delay(KEY_DELAY*2);
     }
	/* Ctrl+X, Cut */
    else if (get_ctrl_key(SCAN_X)) {
      editmenu_cut();
      delay(KEY_DELAY*2);
     }
	/* Ctrl+F, FancyFontt */
    else if (get_ctrl_key(SCAN_F)) {
      editmenu_fontfancy();
      delay(KEY_DELAY*2);
     }
	/* Ctrl+N, NormFont */
    else if (get_ctrl_key(SCAN_N)) {
      editmenu_fontnormal();
      delay(KEY_DELAY*2);
     }

	/* Shift+Ins, Paste */
    else if (get_shift_key(SCAN_KEYPAD_INS)) {
      shift_pressed = FALSE;
      start_select_char = end_select_char = -1;
      start_select_line = end_select_line = -1;
      editmenu_paste();
      delay(KEY_DELAY*2);
     }
	/* Tab character ... 5 spaces */
    else if (key_press[SCAN_TAB] != 0) {
      add_string ("     ");
      delay (KEY_DELAY);
     }
	/* CTRL-Y, delete line */
    else if (get_ctrl_key(SCAN_Y)) {
      delete_node();
      end_select_line = start_select_line = -1;
      end_select_char = start_select_char = -1;
      if (current_line >= num_lines) moveline_rel(-1);
      draw_lines (DRAW_ALL);
      delay(KEY_DELAY * 2);
      ClearKeys();
     }
	/* Delete something */
    else if (key_press[SCAN_BKSP] != 0) {
      del_char (DEL_BACKSPACE);
      delay(KEY_DELAY);
     }
	/* Insert line */
    else if (get_enter_state()) {
      break_line ();
      delay(KEY_DELAY);
     }
	/* Delete something */
    else if (get_del_state()) {
      del_char (DEL_DELETE);
      delay(KEY_DELAY);
     }
	/* Home */
    else if (get_home_state()) {
      movechar_abs(0);
     }
	/* End */
    else if (get_end_state ()) {
      movechar_abs (strlen(edit_current->data));
     }
	/* PGUP Move up faster */
    else if (get_pgup_state()) {
      moveline_rel (-height + 1);
      delay (KEY_DELAY);
     }
	/* PGDN, Move down faster */
    else if (get_pgdn_state()) {
      moveline_rel (height - 1);
      delay (KEY_DELAY);
     }
	/* Move up */
    else if (get_up_state()) {
      moveline_rel (-1);
      delay(KEY_DELAY);
     }
	/* Move down */
    else if (get_down_state()) {
      moveline_rel (1);
      delay(KEY_DELAY);
     }
	/* Move left */
    else if (get_left_state()) {
      movechar_rel (-1);
      delay(KEY_DELAY);
     }
	/* Move Right */
    else if (get_right_state()) {
      movechar_rel(1);
      delay(KEY_DELAY);
     }
	/* Normal character... */
    else if (edit_isalpha(ch)) {
      if (get_shift_state() && shift_pressed)
	shift_pressed = FALSE;

      add_char (ch);
      movechar_rel(1);
     }
	/* Shift Key */
    else if (get_shift_state() && !pre_shift && !shift_pressed && !MouseButtonStatus) {
      pre_shift = TRUE;
      shift_pressed = TRUE;
      start_select_char = end_select_char = current_char;
      start_select_line = end_select_line = current_line + 1;
     }


	/* Reset the text selection */
    if (!get_shift_state() && pre_shift) {
      shift_pressed = FALSE;
      pre_shift = FALSE;
     }

  } while (!quit);

  hide_mouse ();
  clrscr();
  show_mouse();
 }
/*========== End of procedure EDIT_LIST::text_editor() ====================*/


/*========== Attempts to Convert a Book File into Normal Text =============*/
boolean convert_book (DAGBOOK_TYPE *book) {
  int i, j;	/* Loop Counter */
  unsigned int size;
  unsigned char *temp_ptr;
  boolean done_line = FALSE;

  char buffer[101], buf[8];	/* Temp Input Buffer */

	/* Parse each page at a time */
  for (i = 0; i < book->num_pages; i++) {
    temp_ptr = (unsigned char *) book->pages[i];
    buffer[0] = 0;
    size = (unsigned int) (book->page_offsets[i + 1] - book->page_offsets[i]);
    j = 0;

	/* Parse characters at a time */
    while (temp_ptr && j < size) {

      switch (*temp_ptr) {
	case 0xFD:	/* Means next line is centered on screen */
	  chrcat (buffer, CENTER_CHAR);
	  break;
	case 0x01:	/* Unknown */
	  strcat (buffer, "#01");
	  break;
	case 0xFB:	/* Unknown */
	  strcat (buffer, "#FB");
	  temp_ptr++;
	  j++;
	  sprintf (buf, "#%02X", *temp_ptr);
	  temp_ptr++;
	  j++;
	  strcat (buffer, buf);
	  break;
	case 0xF9:	/* Font selection char */
	  temp_ptr++;
	  j++;

	  if (*temp_ptr == 0x02)
	    strcat (buffer, FANCY_FONT_STRING);
	  else
	    strcat (buffer,  NORMAL_FONT_STRING);

	  break;
	case 0xF6:	/* Pause Output, end of page */
	  chrcat (buffer, END_PAGE_CHAR);
	  done_line = TRUE;
	  break;
	case 0:		/* End of line */
	  done_line = TRUE;
	  break;
	default:	/* Normal Character */
	  chrcat (buffer, *temp_ptr);
	  break;
       } /* End of switch */

      if (strlen(buffer) >= MAX_EDIT_LENGTH - 1) {
	chradd (buffer, MAX_EDIT_LENGTH, 0);
	editor.add_tail (buffer);
	memccpy (&buffer[0], &buffer[MAX_EDIT_LENGTH], 0, strlen(&buffer[MAX_EDIT_LENGTH + 1]));
       }

      if (done_line || strlen(buffer) >= MAX_EDIT_LENGTH - 1) {
	editor.add_tail (buffer);
	buffer[0] = 0;
	done_line = FALSE;
       }

      temp_ptr++;
      j++;
     } /* End of while loop */

   } /* End of for loop */

  return (TRUE);
 }
/*========== End of Function convert_dagbook() ============================*/


/*========== Attempts to Convert some Text into a Book File ===============*/
boolean convert_text (DAGBOOK_TYPE *book) {
  EDIT_TYPE *temp_line;	/* Temp Pointer */
  int i;                /* Loop Counter */
  unsigned int buflen, pre_size = 0;
  unsigned long size;
  char *temp_ptr;
  boolean done_page = FALSE, done;
  char *buffer;	/* Temp Input Buffer */
  char buf[8];

	/* Allocate the temp input buffer */
  buffer = create_ptr (64000u);

	/* Clear the book */
  book->destroy();
  temp_line = editor.edit_head;
  buffer[0] = 0;
  size = 0;
  buflen = 0;

	/* Write until one page is found... */
  while (temp_line) {
    temp_ptr = temp_line->data;
    done = FALSE;

	/* Parse each line, a character at a time */
    while (temp_ptr && !done) {
      switch (*temp_ptr) {
	case 0:			/* EOL */
	  buffer[buflen] = 0;
	  done = TRUE;
	  break;
	case END_PAGE_CHAR:	/* Start New Page */
	  buffer[buflen] = 0xF6;

	  if (*(temp_ptr + 1) == 0) {
	    temp_ptr++;
	    done = TRUE;
	   }

	  done_page = TRUE;
	  break;
	case CENTER_CHAR:	/* Center line character */
	  buffer[buflen] = 0xFD;
	  break;
	case HEX_CHAR:		/* Undefined Hexdecimal string */

			/* Make sure its a valid hex... */
	  if (isxdigit(*(temp_ptr + 1)) && isxdigit(*(temp_ptr + 2))) {
	    buf[0] = '0';
	    buf[1] = 'x';
	    buf[2] = *(temp_ptr + 1);
	    buf[3] = *(temp_ptr + 2);
	    buf[4] = 0;
	    buffer[buflen] = (unsigned char) strtol (buf, NULL, 0);
	    temp_ptr += 2;
	   }
	  else
	    chrcat (buffer, *temp_ptr);

	  break;
	case '{':	/* Font Selected Character */
	  if (strnicmp (temp_ptr, FANCY_FONT_STRING, strlen(FANCY_FONT_STRING)) == 0) {
	    buffer[buflen++] = 0xF9;
	    buffer[buflen] = 0x02;
	    temp_ptr += strlen(FANCY_FONT_STRING) - 1;
	   }
	  else if (strnicmp (temp_ptr, NORMAL_FONT_STRING, strlen(NORMAL_FONT_STRING)) == 0) {
	    buffer[buflen++] = 0xF9;
	    buffer[buflen] = 0x04;
	    temp_ptr += strlen(NORMAL_FONT_STRING) - 1;
	   }
	  else
	    buffer[buflen] = *temp_ptr;

	  break;

	default:	/* Regular character */
	  buffer[buflen] = *temp_ptr;
	  break;
       } /* End of switch */

      temp_ptr++;
      buflen++;

		/* Create a new page */
      if (done_page || buflen > 64000u) {
	done_page = FALSE;
	book->pages[book->num_pages] = create_ptr(buflen + 1);
	memcpy (book->pages[book->num_pages], buffer, buflen + 1);
	book->page_offsets[book->num_pages] = (unsigned long) pre_size;
	buffer[0] = 0;
	pre_size = buflen;
	buflen = 0;
	book->num_pages++;
       }
     }

    temp_line = temp_line->next;
   } /* End of While Loop */

	/* Write the last Page, if any */
  if (buflen > 0) {
    book->pages[book->num_pages] = create_ptr(buflen + 1);
    memcpy (book->pages[book->num_pages], buffer, buflen + 1);
    book->page_offsets[book->num_pages] = (unsigned long) pre_size;
    buffer[0] = 0;
    pre_size = buflen;
    buflen = 0;
    book->num_pages++;
   }

	/* Fix the offsets */
  book->page_offsets[book->num_pages] = (unsigned long) pre_size;
  size = book->num_pages * 4 + 10 + 64 + 160 + 2;

  for (i = 0; i <= book->num_pages; i++) {
    size += book->page_offsets[i];
    book->page_offsets[i] = size;
   }

	/* Free Allocated Memory */
  delete buffer;

  return (TRUE);
 }
/*========== End of Function convert_text() ===============================*/


/*========== Cut Copy and Paste Menu Functions ============================*/
void editmenu_copy (__CPPARGS) {
  editor.copy();
 }

void editmenu_cut (__CPPARGS) {
  editor.cut();
 }

void editmenu_paste (__CPPARGS) {
  editor.paste();
 }
/*========== End of Menu Cut/Copy/Paste Functions =========================*/


/*========== Inserts the Font Fancy String ================================*/
void editmenu_fontfancy (__CPPARGS) {
  editor.add_string (FANCY_FONT_STRING);
 }
/*========== End of Procedure editmenu_fontfancy() ========================*/


/*========== Inserts the Font Normal String ===============================*/
void editmenu_fontnormal (__CPPARGS) {
  editor.add_string (NORMAL_FONT_STRING);
 }
/*========== End of Procedure editmenu_fontnormal() =======================*/


/*========== Misc Menu Functions ==========================================*/
void editmenu_center (__CPPARGS) {
  editor.current_char = 0;

  if (editor.edit_current && editor.edit_current->data[0] != CENTER_CHAR) {
    editor.add_char (CENTER_CHAR);
    editor.draw_lines (DRAW_CURRENT);
   }
 }

void editmenu_endpage (__CPPARGS) {
  editor.break_line (FALSE);
  editor.add_current_line (END_PAGE_STRING);
  editor.draw_status_line();
  editor.draw_lines (DRAW_PREVIOUS);
 }
/*========== End of Misc Menu Functions ===================================*/


/*========== The Help window ==============================================*/
void editmenu_help(__CPPARGS) {

  _setcursortype (_NOCURSOR);
  textcolor (BIGWIN_BORD_COLOR);
  textbackground (BIGWIN_BACK_COLOR);

	/* Draw the window */
  draw_textbox (1, 1, 80, 25, "HELP: BookEdit - DF Book Text Editor", BIGWIN_TEXT_COLOR);

  hide_mouse();

  textcolor (BLUE);
  cprintf_centx (3, "BookEdit v%s - Text Editor - by Dave Humphrey", BOOKEDIT_VERSION);

  textcolor (BIGWIN_TEXT_COLOR);
  gotoxy (4, 5);
  cprintf ("The text editor used in DF BookEdit is a basic one, much like the DOS");
  gotoxy (4, 6);
  cprintf ("editor Edit. Mouse and key combinations are supported and special text");
  gotoxy (4, 7);
  cprintf ("codes are displayed in different colors. Read the manual document");
  gotoxy (4, 8);
  cprintf ("BOOKEDIT.TXT for more information.");

  gotoxy (5, 10);
  cprintf ("Editor Key and Mouse Commands");
  gotoxy (8, 11);
  cprintf ("%c%c%c%c / PgUP / PgDN / Home / End / Mouse - Move around text area", 27, 24, 25, 26);
  gotoxy (8, 12);
  cprintf ("F1 - This Help Screen           ALT+Q - Quit Text Editor");
  gotoxy (8, 13);
  cprintf ("F2 - Save Book File             ALT+F - Activate File Menu");
  gotoxy (8, 14);
  cprintf ("F3 - Load Book File             CTRL+Y - Delete Current Line");

  gotoxy (5, 16);
  cprintf ("Special Color Text Codes");

  gotoxy (8, 17);
  textcolor (FONT_TEXT_COLOR);
  textbackground (FONT_BACK_COLOR);
  cprintf ("{FancyFont} {NormFont}");
  textcolor (BIGWIN_TEXT_COLOR);
  textbackground (BIGWIN_BACK_COLOR);
  cprintf (" - Font Type");

  gotoxy (48, 17);
  textcolor (END_PAGE_TEXT_COLOR);
  textbackground (END_PAGE_BACK_COLOR);
  cprintf ("%c", END_PAGE_CHAR);
  textcolor (BIGWIN_TEXT_COLOR);
  textbackground (BIGWIN_BACK_COLOR);
  cprintf (" - End of Page (Max 23 Lines)");

  gotoxy (8, 18);
  textcolor (CR_TEXT_COLOR);
  textbackground (CR_BACK_COLOR);
  cprintf ("%c", CENTER_CHAR);
  textcolor (BIGWIN_TEXT_COLOR);
  textbackground (BIGWIN_BACK_COLOR);
  cprintf (" - A Centered Text Line");

  gotoxy (48, 18);
  textcolor (HEX_TEXT_COLOR);
  textbackground (HEX_BACK_COLOR);
  cprintf ("%c00", HEX_CHAR);
  textcolor (BIGWIN_TEXT_COLOR);
  textbackground (BIGWIN_BACK_COLOR);
  cprintf (" - Undefined Text Code");

  gotoxy (5, 20);
  cprintf ("Initial / Current Available Memory: %ld / %ld bytes", initial_far_heapsize, farcoreleft());
  gotoxy (5, 21);
  cprintf ("Status of Far Heap: ");

  switch (farheapcheck()) {
    case _HEAPCORRUPT: cprintf ("Heap has been Corrupted - You Should Reboot!"); break;
    case _HEAPOK: cprintf ("Heap OK"); break;
    default: cprintf ("No heap"); break;
   };

  textcolor (RED);
  cprintf_centx (23, "Press Any Key to Continue...");
  textcolor (BIGWIN_TEXT_COLOR);
  textbackground (BIGWIN_BACK_COLOR);

  show_mouse();
  getch();
 }
/*========== End of procedure void editmenu_help() ========================*/


/*========== Does the Load Text Menu Command ==============================*/
void editmenu_load (__CPPARGS) {
  char *buffer;

	/* Make sure not to overwrite things */
  if (editor.modified && !get_yn_choice("File Not Saved", "Current File Not Saved! Continue"))
    return;

	/* Allocate temp buffer and set to nothing*/
  buffer = create_ptr (MAX_EDIT_LENGTH + 1);
  buffer[0] = 0;

	/* Input filename to load */
  if (file_dialogue(buffer, &text_path[0], "Load Text", "Load", "*.txt")) {

		/* If successful, try and load the file... */
    if (load_editfile (buffer)) {
      if (editor.edit_filename) delete editor.edit_filename;
      editor.edit_filename = create_ptr (buffer);
      editor.file_loaded = TRUE;
      editor.modified = FALSE;
     }
    else {
      error_box ("ERROR: Load Text", "Could not Load file '%s'!\n%s", buffer, dagbutil_errmsg[dagb_error]);
     }
   }

  delete buffer;
  editor.draw_lines (DRAW_ALL);
 }
/*========== End of procedure editmenu_load() =============================*/


/*========== Does load command for a DF Book File =========================*/
void editmenu_loadbook (__CPPARGS) {
  char *buffer;

	/* Make sure not to overwrite things */
  if (editor.modified && !get_yn_choice("File Not Saved", "Current File Not Saved! Continue"))
    return;

	/* Allocate temp buffer and set to nothing*/
  buffer = create_ptr (MAX_EDIT_LENGTH + 1);
  buffer[0] = 0;

	/* Input filename to load */
  if (file_dialogue(buffer, &text_path[0], "Load Book", "Load", "*.txt")) {

	/* Clear the current book structure */
    dagbook.destroy();

		/* If successful, try and load the file... */
    if (dagbook.load_book(buffer)) {
      if (editor.edit_filename) delete editor.edit_filename;
      editor.edit_filename = create_ptr (buffer);

		/* Need to clear the text area... */
      editor.destroy();

		/* Convert the book to a useable format */
      convert_book(&dagbook);

      editor.file_loaded = TRUE;
      editor.modified = FALSE;
     }
    else {
      error_box ("ERROR: Load Book Text", "Could not Load Book File '%s'!\n%s", buffer, dagbutil_errmsg[dagb_error]);
     }

	/* Destroy the book text now that we are done */
    dagbook.destroy();
   }

  delete buffer;
  editor.draw_lines (DRAW_ALL);
 }
/*========== End of procedure editmenu_loadbook() =========================*/


/*========== Does new command =============================================*/
void editmenu_new (__CPPARGS) {

	/* Clear the array */
  editor.destroy();

	/* Init the list */
  editor.init();

	/* Redraw Screen... */
  editor.draw_lines (DRAW_ALL);

	/* Will also need to destroy and reinit the dagbook structure */
  dagbook.destroy();
  dagbook.init();

  return;
 }
/*========== End of procedure editmenu_new() ==============================*/


/*========== Does quit command ============================================*/
void editmenu_quit (__CPPARGS) {
  if (editor.modified) {
    if (get_yn_choice("Exit BookEdit", "File Not Saved! Do you Really Wish to Exit"))
      quit = TRUE;
   }
  else
    quit = TRUE;

 }
/*========== End of procedure editmenu_quit() =============================*/


/*========== Does save command ============================================*/
void editmenu_save (__CPPARGS) {
  char *buffer;

	/* Allocate Temp Buffer */
  buffer = create_ptr (MAX_EDIT_LENGTH + 1);

	/* If file is loaded in memory, set filename */
  if (editor.file_loaded && editor.edit_filename)
    strcpy(buffer, editor.edit_filename);
  else
    *buffer = 0;	/* Set filename to nothing if nothing loaded */

	/* Get filename to save text as... */
  if (file_dialogue(buffer, &text_path[0], "Save Text", "Save", "*.txt")) {

	/* If input is sucessful, save file... */
    if (save_editfile(buffer)) {
      if (editor.edit_filename) delete editor.edit_filename;
      editor.edit_filename = create_ptr (buffer);
      editor.file_loaded = TRUE;
      editor.modified = FALSE;
     }
    else {
      error_box ("ERROR: Save Text", "Could not Save file '%s'\n%s", buffer, dagbutil_errmsg[dagb_error]);
     }
   }

  delete buffer;
 }
/*========== End of procedure editmenu_save() =============================*/


/*========== Saves a Book File ============================================*/
void editmenu_savebook (__CPPARGS) {
  char *buffer;

	/* Allocate Temp Buffer */
  buffer = create_ptr (MAX_EDIT_LENGTH + 1);

	/* If file is loaded in memory, set filename */
  if (editor.file_loaded && editor.edit_filename)
    strcpy(buffer, editor.edit_filename);
  else
    *buffer = 0;	/* Set filename to nothing if nothing loaded */

	/* Get filename to save text as... */
  if (file_dialogue(buffer, &text_path[0], "Save Book Text", "Save", "*.txt")) {

	/* First, convert the text into the DAGBOOK format */
    convert_text (&dagbook);

	/* If input is sucessful, save file... */
    if (dagbook.save_book(buffer)) {
      if (editor.edit_filename) delete editor.edit_filename;
      editor.edit_filename = create_ptr (buffer);
      editor.file_loaded = TRUE;
      editor.modified = FALSE;
     }
    else {
      error_box ("ERROR: Saving Book Text", "Could not Save Book File '%s'!\n%s", buffer, dagbutil_errmsg[dagb_error]);
     }

	/* Destroy the bookfile now that we are done with it */
     dagbook.destroy();
   }

  delete buffer;
 }
/*========== End of procedure editmenu_savebook() =========================*/


/*========== Change the Book Author =======================================*/
void editmenu_author (__CPPARGS) {
  char buffer[41];

  strncpy (buffer, dagbook.author, 40);
  buffer[40] = 0;

  if (get_input (buffer, 40, 50, 12, "Change Book Author", "Enter the New Author for the Book"))
    strcpy (dagbook.author, buffer);
 }
/*========== End of Procedure editmenu_author() ===========================*/


/*========== Change the Book Title ========================================*/
void editmenu_title (__CPPARGS) {
  char buffer[41];

  strncpy (buffer, dagbook.title, 40);
  buffer[40] = 0;

  if (get_input (buffer, 40, 50, 12, "Change Book Title", "Enter the New Title for the Book"))
    strcpy (dagbook.title, buffer);
 }
/*========== End of Procedure editmenu_title() ============================*/


/*========== Attempts to load a Text File =================================*/
boolean load_editfile (char far *filename) {
  FILE *f;	/* File pointer */
  int i;	/* Loop counter */
  char ch;	/* Temp string buffer */
  char buffer[MAX_EDIT_LENGTH + 1];

	/* Attempt to open the file for reading */
  if (!(f = openfile (filename, "rt")))
    return (FALSE);

	/* Clear the array */
  editor.destroy();
  buffer[0] = 0;
  i = 0;

  do {
    ch = fgetc(f);	/* Read a character */

    if (ch == EOF) {	/* End of file... */
      if (i > 0) editor.add_tail(buffer);
      break;
     }
    else if (ch == 9) { /* Tab Character */
      if (i + 5 >= MAX_EDIT_LENGTH) { /* Make sure we don't exceed the maximum length */
	editor.add_tail(buffer);
	strcpy (buffer, "     ");
	i = 5;
       }
      else { /* Simply add onto end */
	strcat (buffer, "     ");
	i += 5;
       }
     }
    else if (ch == 10) { /* CR */
      editor.add_tail(buffer);
      buffer[0] = 0;
      i = 0;
     }
    else if (i < MAX_EDIT_LENGTH) { /* Append to end of buffer */
      buffer[i] = ch;
      i++;
      buffer[i] = 0;
     }
    else { /* End of line */
      editor.add_tail(buffer);
      buffer[1] = 0;
      buffer[0] = ch;
      i = 1;
     }

  } while(TRUE);	/* Read file until EOF is read */

  fclose (f);
  return (TRUE);
 }
/*========== End of procedure load_editfile() =============================*/


/*========== Attempts to save a text file =================================*/
boolean save_editfile (char *filename) {
  FILE *f;		/* File pointer */
  EDIT_TYPE far *line;	/* Temp pointer */

	/* Does file exist? */
  if (fileexists(filename)) {

	/* Make sure user wants to overwrite file... */
    if (!get_yn_choice("Warning: File Exists", "File '%s' exists, Overwrite", filename))
      return (FALSE);

   }

	/* Attempt to open file for writing */
  if (!(f = openfile (filename, "wt")))
    return (FALSE);

  line = editor.edit_head;

  do {	/* Save all the data */
    fprintf (f, "%s\n", line->data);
    line = line->next;
  } while(line != NULL);

  fputc (EOF, f);	/* Write the End-Of-File marker */

  fclose (f);
  return(TRUE);
 }
/*========== End of procedure save_editfile() =============================*/


/*========== Routines run when program is stopped =========================*/
void exit_bookedit(void) {

  textmode(C80);	/* Normal text mode */
  printf ("Returned to textmode (80x25)\n");

	/* Reset to original drive and directory */
  setdisk (orig_disk);

  if (chdir (orig_dir) == -1)
    printf ("Failed to restore original path!\n");

	/* Replace our own keyboard interrupt routine with the original */
  delete_keyboard ();
  printf ("Replaced original keyboard driver\n");

  printf ("Freeing allocated memory\n");
  editor.destroy();
  editor.clip_destroy();
  printf ("     Freed all allocated memory\n");
  printf ("Initial/Final Available Memory Check: %ld / %ld bytes\n", initial_far_heapsize, farcoreleft());

  if (initial_far_heapsize - farcoreleft() != 0)
    printf ("     WARNING: Memory may not be fully freed?\n");

  printf ("farheapcheck() returns ");

  switch (farheapcheck()) {
    case _HEAPCORRUPT: printf ("Heap has been Corrupted - You Should Reboot!\n"); break;
    case _HEAPOK: printf ("Heap OK\n"); break;
    default: printf ("No heap\n"); break;
   };

  printf ("Finished clean-up of BOOKEDIT v%s\n\n", BOOKEDIT_VERSION);
 }
/*========== End of procedure exit_bookedit() =============================*/


/*========== Initializes everything =======================================*/
void init_bookedit (void) {

	/* No scrolling of text on screen */
  _wscroll = 0;

	/* Save initial available memory */
  initial_far_heapsize = farcoreleft();

	/* Define exit procedure */
  atexit (exit_bookedit);

	/* Set the maximum string length */
  max_string_length = MAX_STRING_LENGTH;

	/* Intialize the Default Buttons in UTIL.CPP */
  init_buttons ();

	/* Define the strings used in case of a bug... */
  err_header_string = &bookedit_title[0];
  err_header_version = &bookedit_version[0];

	/* Print opening title.... */
  printf ("BOOKEDIT v%s - Copyright (c) 1997 - by Dave Humphrey\n\n", BOOKEDIT_VERSION);

	/* Save the current directory and drive...for reseting at end and
	 * goto intial directory */
  if (getcwd (&orig_dir[0], MAX_STRING_LENGTH) == NULL)
    printf ("ERROR: Path too Long, Path length cannot exceed 80 bytes!\n\n");

  orig_disk = getdisk();

	/* Replace some DOS error handling routines with our own */
  harderr (dos_err_handler);
  ctrlbrk (ctrl_brk_handler);
  setcbrk(1);
  printf ("Replaced DOS error handler and CTRL-BRK routines\r\n");

	/* Replace keyboard interrupt with our own routine */
  printf ("Replace default keyboard interrupt\r\n");
  install_keyboard ();
  ClearKeys();
  printf ("     Keyboard interrupt replaced\n");

	/* Initialize the Mouse Driver */
  printf ("Initialize Mouse Driver\r\n");
  if (!mouse_init()) bug ("Could not initialize mouse driver!", NULL);

	/* Some Mouse Cursor Stuff */
  asm {
    mov ax, 0x0A
    mov bx, 0
    mov cx, 0xFF00
    mov dx, 0x0108
    int 0x33
   };

  printf ("    Mouse Driver Initialized\r\n");

	/* Goto various text modes and Show mouse cursor */
  if (high_textmode) {
    textmode(64);
    mouse_window (0, 0, 319, 299);
   }
  else
    mouse_window (0, 0, 319, 199);

  show_mouse ();
 }
/*========== End of procedure init_bookedit() =============================*/


/*========== Begin Main Procedure =========================================*/
boolean main (void) {

  open_log_file ("bookedit.log");
  init_bookedit();

	/* Attempt to change directory */
//  chdir ("arena2\\books");


  editor.text_editor ("DF Book Editor");

  return (TRUE);
 }
/*========== End Main Program =============================================*/