| home | contents | previous | next page | send comment | send link | add bookmark |

IDE_MAIN.CPP

main editor file

/*-------------------------------------------------------------------*
     Screen Editor

     Main file for editor of ascii text files

     Compile using large memory model.

     File:     ide_main.cpp

     Module:   editor

     Link to:  ide_menu.cpp

     by:  Stephen R. Schmitt
 *-------------------------------------------------------------------*/

#include "ide_data.h"

/*-------------------------------------------------------------------*
    Data Section
 *-------------------------------------------------------------------*/

/*
 *   external declarations
 */
extern FILE *Program;
extern char File_name[];
extern bool File_changed;

/*
 *   global declarations
 */
struct line *First_line,                            // pointer to first line
            *Text_line,                             // pointer to current line
            *Last_line;                             // pointer to last line
struct line *Clip_first_line;                       // start of clipboard
struct edit Select_begin,                           // beginning of selected text
            Select_end;                             // ending of selected text
bool Select_text;                                   // text selected flag
int Text_line_num;                                  // current text line number
int Last_line_num;                                  // number of last text line
int Lin;                                            // current screen line
int Col;                                            // current screen column
int Top = 2;                                        // top line of screen
int Bottom = 25;                                    // bottom line of screen
int Right = 80;                                     // right column of screen
int Left = 1;                                       // left column of screen
int Tab_size = 4;                                   // default tab size
int Msg_col = 70;                                   // column for messages
int Msg_lin = 1;                                    // line for messages
bool Insert;                                        // insert/overwrite flag
bool Run_editor;                                    // loop flag
char *Screen_buffer;                                // full screen buffer
char *Dos_screen;                                   // full screen buffer
int Dos_lin, Dos_col;                               // Dos screen data

/*-------------------------------------------------------------------*
    Code Section
 *-------------------------------------------------------------------*/

void main(int argc, char *argv[])
{
    union scancode key;
    bool  usage_message = false;

    // save dos screen
    Dos_screen = new char[4000];
    if (Dos_screen == NULL)
        Run_editor = false;
    else
    {
        Dos_col = wherex();
        Dos_lin = wherey();
        gettext(1, 1, 80, 25, Dos_screen);
    }

    Screen_buffer = new char[4000];
    if (Screen_buffer == NULL)
        Run_editor = false;
    else if (argc == 2)                             // command line file name
    {
        Program = fopen(argv[1], "r+");
        if (Program == NULL)
        {
            usage_message = true;
            Run_editor = false;
        }
        else
        {
            file_new();
            strcpy(File_name, argv[1]);
            file_load_process();
            Run_editor = true;
        }
    }
    else
    {
        file_new();
        Run_editor = true;
    }

    // loop indefinitely while reading keyboard
    while (Run_editor == true)
    {
        cursor_position();

        key.ch = get_key();                         // get next input

        switch (key.c[0])
        {
        case  0:
            function_key(key.c[1]);
            break;

        case  2: /* Ctrl+B keys */
        case  5: /* Ctrl+E keys */
        case 18: /* Ctrl+R keys */
            select_text(key.c[0]);
            break;

        case  3: /* Ctrl+C keys */
            copy_text();
            break;

        case  4: /* Ctrl+D keys */
            delete_text();
            break;

        case  8: /* Backspace key */
            backspace();
            break;

        case  9: /* Tab key */
            File_changed = true;
            tab_right();
            break;

        case 13: /* Enter key */
            File_changed = true;
            enter_line();
            break;

        case 16: /* Ctrl+P keys */
            File_changed = true;
            paste_text();
            break;

        case 20: /* Ctrl+T keys */
            File_changed = true;
            copy_text();
            delete_text();
            break;

        case 22: /* Ctrl+V keys */
            copy_text();
            delete_text();
            paste_text();
            break;

        case 25: /* Ctrl+Y keys */
            File_changed = true;
            delete_line();
            break;

        default:
            if (Col == Right)
                /* do nothing : at end of line */;
            else if (isprint(key.c[0]))
            {
                File_changed = true;
                if (Insert == true)
                    insert_character(key.c[0]);
                else
                    overwrite_character(key.c[0]);
            }
            break;
        }
    }

    _setcursortype(_NORMALCURSOR);
    window(1, 1, 80, 25);
    puttext(1, 1, 80, 25, Dos_screen);
    gotoxy(Dos_col, Dos_lin);

    assert(Dos_screen != NULL);
    delete Dos_screen;
    assert(Screen_buffer != NULL);
    delete Screen_buffer;

    if (usage_message)
    {
        printf("\n\n");
        printf("\t\t T Editor\n\n");
        printf("\t\t Usage: te [filename.ext]\n\n");
        printf("\t\t Author:\n\n");
        printf("\t\t\t Stephen R. Schmitt\n\n\n\n");
    }

    exit(0);
}

/*
 *   "cursor_position" update cursor position indicator and the
 *   message block
 *
 *   returns:  nothing
 */
void cursor_position()
{
    textcolor(LIGHTGRAY);
    gotoxy(Left, Top - 1);
    clreol();
    cprintf("  %d:%d  ", Text_line_num, Col);
    gotoxy(30, 1);
    cputs(File_name);
    gotoxy(Msg_col, Msg_lin);
    cprintf("F10 Help  ");
    textcolor(WHITE);
    gotoxy(Col, Lin);
}

/*
 *   "function_key" selects an action when a function key is pressed
 *
 *   returns:  nothing
 */
void function_key(unsigned char key)                // of function key
{
    switch (key)
    {
    case 15: /* Shift+Tab keys */
        File_changed = true;
        tab_left();
        break;

    case 59: /* F1 key */
        files();
        break;

    case 60: /* F2 key */
        gettext(1, 1, 80, 25, Screen_buffer);
        file_save();
        File_changed = false;
        break;

    case 61: /* F3 key */
        production();
        break;

    case 62: /* F4 key */
        search();
        break;

    case 68: /* F10 key */
        help();
        break;

    case 71: /* Home key */
        Col = Left;
        gotoxy(Col, Lin);
        break;

    case 72: /* up arrow key */
        up_arrow();
        break;

    case 73: /* Page Up key */
        page_up();
        break;

    case 75: /* left arrow key */
        left_arrow();
        break;

    case 77: /* right arrow key */
        right_arrow();
        break;

    case 79: /* End key */
        end();
        break;

    case 80: /* down arrow key */
        down_arrow();
        break;

    case 81: /* Page Down key */
        page_down();
        break;

    case 82: /* Insert key */
        switch_insert_overwrite();
        delay(1000);
        break;

    case 83: /* Delete key */
        File_changed = true;
        delete_character();
        break;

    case 114: /* Ctrl + Print Screen key */
        save_screen();
        break;

    case 118: /* Ctrl + Page Down key */
        goto_end_of_file();
        break;

    case 132: /* Ctrl + Page Up key */
        goto_start_of_file();
        break;

    default:
        break;
    }
}

/*-------------------------------------------------------------------*
    Text Editing Functions
 *-------------------------------------------------------------------*/

/*
 *   "get_key" obtains a two byte character code from the keyboard 
 *
 *   returns:  the scancode of the key
 */
int get_key()
{
    union REGS r;

    r.h.ah = 0;
    return int86(0x16, &r, &r);
}

/*
 *   "first_text_line" sets editor to first text line 
 *
 *   returns:  new text line number
 */
int first_text_line()
{
    assert(First_line != NULL);
    Text_line = First_line;
    Text_line_num = 1;
    return Text_line_num;
}

/*
 *   "incr_text_line" sets editor to next text line 
 *
 *   returns:  new text line number
 */
int incr_text_line()
{
    assert(Text_line != NULL);
    Text_line = Text_line->next;
    Text_line_num++;
    return Text_line_num;
}

/*
 *   "decr_text_line" sets editor to previous text line 
 *
 *   returns:  new text line number
 */
int decr_text_line()
{
    assert(Text_line != NULL);
    Text_line = Text_line->prev;
    Text_line_num--;
    return Text_line_num;
}

/*
 *   "enter_line" adds a new line of text by allocating a new line
 *   structure and re-connecting pointers.
 *
 *   returns:  nothing
 */
void enter_line()
{
    line *new_line = new line;
    if (new_line == NULL)
    {
        gettext(1, 1, 80, 25, Screen_buffer);
        error_message("System is out of memory!");
        get_key();
        restore_edit_window();
        return;
    }

    memset(new_line->string, '\0', MAX_LINE_LENGTH);

    // rearrange pointers
    line *above = Text_line;
    line *below = Text_line->next;

    above->next = new_line;
    new_line->prev = above;
    new_line->next = below;
    below->prev = new_line;

    // move characters from cursor to the end of the line to the new line
    int i = Col - 1;
    int j = 0;
    while ((above->string[i] != NULL)&&(i < MAX_LINE_LENGTH - 1))
    {
        new_line->string[j] = above->string[i];
        above->string[i] = NULL;
        i++;
        j++;
    }
    new_line->string[j] = NULL;

    // update display and reset cursor
    clreol();                                       // current line
    if (Lin == Bottom)                              // at bottom of screen
    {
        // move all lines in text screen up by one line
        movetext(Left, Top + 1, Right, Bottom, Left, Top);
    }
    else
    {
        // move all lines below current line down by one line
        Lin++;
        movetext(Left, Lin, Right, Bottom - 1, Left, Lin + 1);
    }

    if (Select_text)
    {
        if (Select_begin.line_num > Text_line_num)
        {
            Select_begin.line_num++;
            Select_end.line_num++;
        }
        else if (Select_end.line_num > Text_line_num)
            Select_end.line_num++;

        if ((Select_begin.line_num == Text_line_num) &&
            (Select_begin.char_num >= Col - 1))
        {
            // select begins on the new line
            Select_begin.line_num++;
            Select_begin.char_num = Select_begin.char_num - Col + 1;
        }

        if ((Select_end.line_num == Text_line_num) &&
            (Select_end.char_num >= Col - 1))
        {
            // select ends on the new line
            Select_end.line_num++;
            Select_end.char_num = Select_end.char_num - Col + 1;
        }
    }

    Text_line_num++;                                // update editor
    Text_line = new_line;
    Last_line_num++;

    write_line(Text_line, Text_line_num, Lin);

    Col = Left;                                     // on the new line
    gotoxy(Col, Lin);
}

/*
 *   "delete_line" removes a line of text by re-connecting pointers
 *   and deallocating the line structure.
 *
 *   returns:  nothing
 */
void delete_line()
{
    int j, text_num;
    line *text;
    line *above = Text_line->prev;
    line *below = Text_line->next;

    if (Select_text)
    {
        if (Select_begin.line_num > Text_line_num)
        {
            Select_begin.line_num--;
            Select_end.line_num--;
        }
        else if (Select_end.line_num > Text_line_num)
            Select_end.line_num--;

        if ((Select_begin.line_num == Text_line_num) &&
            (Select_end.line_num   == Text_line_num))
        {
            // clear select
            Select_begin.line_ptr = NULL;
            Select_begin.line_num = 0;
            Select_begin.char_num = 0;
            Select_end.line_ptr = NULL;
            Select_end.line_num = 0;
            Select_end.char_num = 0;
        }
        else if (Select_begin.line_num == Text_line_num)
        {
            // select begins on the line below
            Select_begin.char_num = 0;
        }
        else if (Select_end.line_num == Text_line_num)
        {
            // select ends on the line below
            Select_end.char_num = 0;
        }
    }

    if (above == NULL)                              // on first line
    {
        if (below == Last_line)                     // only one line
        {
            // just remove data; note: should never be on the last line
            Col = Left;
            gotoxy(Col, Lin);
            clreol();                               // clear screen

            strnset(Text_line->string, 0, MAX_LINE_LENGTH);
        }
        else                                        // more than one line
        {
            // first copy string from line below and reconnect pointers
            strnset(Text_line->string, 0, MAX_LINE_LENGTH);
            strcpy(Text_line->string, below->string);
            text = below;
            below = below->next;
            Text_line->next = below;
            below->prev = Text_line;

            // then free the line below and move the text screen up by one line
            assert(text != NULL);
            delete text;
            movetext(Left, Lin + 1, Right, Bottom, Left, Lin);
            gotoxy(Left, Bottom);
            clreol();

            // then fill in bottom line if there is one
            j = Lin;
            text_num = Text_line_num;
            text = Text_line;
            while ((j < Bottom) && (text_num < Last_line_num))
            {
                text = text->next;
                text_num++;
                j++;
            }

            if (j == Bottom)
                write_line(text, text_num, j);

            // reset the editor
            Last_line_num--;
            Col = Left;
            gotoxy(Col, Lin);
        }
    }
    else                                            // not on first line
    {
        // first reconnect pointers
        above->next = below;
        below->prev = above;

        // free current text line and move all lines
        // in text screen from line below up by one
        assert(Text_line != NULL);
        delete Text_line;
        Text_line = below;
        movetext(Left, Lin + 1, Right, Bottom, Left, Lin);
        gotoxy(Left, Bottom);
        clreol();

        // then fill in bottom line if there is one
        j = Lin;
        text_num = Text_line_num;
        text = Text_line;
        while ((j < Bottom)&&(text_num < Last_line_num))
        {
            text = text->next;
            text_num++;
            j++;
        }

        if (j == Bottom)
            write_line(text, text_num, j);

        // reset the editor; the line below gets the line number of
        // the deleted line unless deletion of a text line puts the
        // cursor on the last line
        Last_line_num--;
        if (Text_line == Last_line)
            up_arrow();
        Col = Left;
            gotoxy(Col, Lin);
    }
}

/*
 *   "insert_character" adds a new character to the current text line
 *
 *   returns:  nothing
 */
void insert_character(char ch)                      // character to enter
{
    // find end of line and shift characters right
    int i = Col - 1;
    while (Text_line->string[i] != NULL)
        i++;

    while (i >= Col - 1)
    {
        Text_line->string[i + 1] = Text_line->string[i];
        i--;
    }

    Text_line->string[Col - 1] = ch;

    // this ensures that lines will not exceed available space
    Text_line->string[MAX_LINE_LENGTH - 1] = NULL;

    // if nulls are on the right of the new character, fill in with spaces
    i = Col - 2;
    while (i >= 0)
    {
        if (Text_line->string[i] == NULL)
            Text_line->string[i] = ' ';
        else
            break;

        i--;
    }

    if (Select_text)
    {
        if ((Select_begin.line_num == Text_line_num)&&
            (Select_begin.char_num > Col - 1))
            Select_begin.char_num++;

        if ((Select_end.line_num == Text_line_num)&&
            (Select_end.char_num > Col - 1))
            Select_end.char_num++;
    }

    // update display and reset cursor
    write_line(Text_line, Text_line_num, Lin);
    Col++;
    gotoxy(Col, Lin);
}

/*
 *   "overwrite_character" replaces a character in the current
 *   text line
 *
 *   returns:  nothing
 */
void overwrite_character(char ch)                   // character to enter
{
    Text_line->string[Col - 1] = ch;

    // if nulls are on the right of the new character, fill in with spaces
    int i = Col - 2;
    while (i >= 0)
    {
        if (Text_line->string[i] == NULL)
            Text_line->string[i] = ' ';
        else
            break;

        i--;
    }

    // update display and reset cursor
    putch(ch);
    Col++;
    gotoxy(Col, Lin);
}

/*
 *   "delete_character" removes a character from the current test line
 *
 *   returns:  nothing
 */
void delete_character()
{
    // shift characters left
    int i = Col - 1;
    while (i < MAX_LINE_LENGTH)
    {
        Text_line->string[i] = Text_line->string[i + 1];
        if (Text_line->string[i] == NULL)
            break;
        i++;
    }

    if (Select_text)
    {
        if ((Select_begin.line_num == Text_line_num)&&
            (Select_begin.char_num > Col - 1))
            Select_begin.char_num--;

        if ((Select_end.line_num == Text_line_num)&&
            (Select_end.char_num > Col - 1))
            Select_end.char_num--;
    }

    write_line(Text_line, Text_line_num, Lin);
    gotoxy(Col, Lin);
}

/*
 *   "switch_insert_overwrite" toggles the character insertion mode
 *
 *   returns:  nothing
 */
void switch_insert_overwrite()
{
    textcolor(YELLOW);

    if (Insert)
    {
        Insert = false;
        gotoxy(Msg_col, Msg_lin);
        cputs("overwrite");
        _setcursortype(_SOLIDCURSOR);
    }
    else
    {
        Insert = true;
        gotoxy(Msg_col, Msg_lin);
        cputs("insert   ");
        _setcursortype(_NORMALCURSOR);
    }

    textcolor(WHITE);
    gotoxy(Col, Lin);
}

/*
 *   "backspace" deletes the character to the left of the cursor
 *   and moves it one space left
 *
 *   returns:  nothing
 */
void backspace()
{
    int offset,                                     // end of line above
        length;                                     // of current line
    line *above;                                    // above current line

    if (Col > Left)
    {
        Col--;
        delete_character();
    }
    else if (Text_line_num > 1)                     // below first line
    {
        above = Text_line->prev;
        length = strlen(Text_line->string);
        offset = strlen(above->string);

        if ((offset + length) < MAX_LINE_LENGTH)
        {
            if (Select_text)
            {
                if (Select_begin.line_num == Text_line_num)
                {
                    Select_begin.line_num--;
                    Select_begin.char_num = Select_begin.char_num + offset;
                }

                if (Select_end.line_num == Text_line_num)
                {
                    Select_end.line_num--;
                    Select_end.char_num = Select_end.char_num + offset;
                }
            }

            strcat(above->string, Text_line->string);
            delete_line();
            Col = offset + 1;
            if (Col > Right)
                Col = Right;

            if (Text_line_num == Last_line_num)
                gotoxy(Col, Lin);
            else
                up_arrow();

            write_line(Text_line, Text_line_num, Lin);
        }
        else
        {
            textcolor(YELLOW);
            gotoxy(Msg_col, Msg_lin);
            cputs("too long  ");
            delay(1000);
        }
    }
}

/*
 *   "tab_right" moves the cursor right by Tab_size spaces and
 *   inserts spaces
 *
 *   returns:  nothing
 */
void tab_right()
{
    if (Col < Right - Tab_size)
    {
        int n = Tab_size - ((Col - Left) % Tab_size);
        for (int i = 0; i < n; i++)
            insert_character(' ');
    }
}

/*
 *   "tab_left" moves the cursor left by Tab_size spaces and
 *   deletes characters
 *
 *   returns:  nothing
 */
void tab_left()
{
    if (Col >= Left + Tab_size)
    {
        int n = Tab_size - ((Col - Left) % Tab_size);
        for (int i = 0; i < n; i++)
            backspace();
    }
}

/*
 *   "up_arrow" moves the cursor up
 *
 *   returns:  nothing
 */
void up_arrow()
{
    if (Text_line_num == 1)
        /* do nothing */;
    else if (Lin == 2)
    {
        // move screen down
        movetext(1, 2, 80, 24, 1, 3);
        decr_text_line();
        gotoxy(1, 2);
        write_line(Text_line, Text_line_num, Lin);
    }
    else
    {
        decr_text_line();
        Lin--;
    }
    gotoxy(Col, Lin);
}

/*
 *   "page_up" moves the screen down by 20 lines toward the beginning
 *   of the file
 *
 *   returns:  nothing
 */
void page_up()
{
    // find text line which is to be at top of text screen
    int top_line = Text_line_num - (Lin - Top);
    int next_top_line = top_line - 20;

    if (next_top_line <= 1)
    {
        next_top_line = 1;
        first_text_line();
    }
    else
    {
        while (next_top_line != Text_line_num)
            decr_text_line();
    }

    write_screen(Text_line, Text_line_num);

    // reset editor
    int j = Top;
    while (j != Lin)
    {
        if (Text_line_num == Last_line_num)
        {
            Lin = j;
            break;
        }
        else
        {
            incr_text_line();
            j++;
        }
    }
    gotoxy(Col, Lin);
}

/*
 *   "left_arrow" moves the cursor left
 *
 *   returns:  nothing
 */
void left_arrow()
{
   if (Col > Left)
   {
      Col--;
      gotoxy(Col, Lin);
   }
}

/*
 *   "right_arrow" moves the cursor right but no farther than first
 *   end of line null.
 *
 *   returns:  nothing
 */
void right_arrow()
{
    if (Col == Right)
        /* do nothing */;
    else
    {
        Col++;
        gotoxy(Col, Lin);
    }
}

/*
 *   "end" moves the cursor to the end of the current line
 *
 *   returns:  nothing
 */
void end()
{
    int i = 0;
    while (Text_line->string[i] != NULL)
        i++;

    if (i < Right)
    {
        Col = i + 1;
        gotoxy(Col, Lin);
    }
    else
    {
        textcolor(YELLOW);
        gotoxy(Msg_col, Msg_lin);
        cputs("too long  ");
        delay(1000);
    }
}

/*
 *   "down_arrow" moves the cursor down
 *
 *   returns:  nothing
 */
void down_arrow()
{
    if (Text_line_num == Last_line_num)
        /* do nothing */;
    else if (Lin == 25)
    {
        // move screen up
        movetext(1, 3, 80, 25, 1, 2);
        incr_text_line();
        gotoxy(1, 25);
        write_line(Text_line, Text_line_num, Lin);
    }
    else
    {
        incr_text_line();
        Lin++;
    }
    gotoxy(Col, Lin);
}

/*
 *   "page_down" moves the screen up by 20 lines
 *
 *   returns:  nothing
 */
void page_down()
{
    // find text line which is to be at top of text screen
    int top_line = Text_line_num - (Lin - Top);
    int next_top_line = top_line + 20;

    if (next_top_line < Last_line_num)
    {
        if (next_top_line > Text_line_num)
        {
            while (next_top_line != Text_line_num)
                incr_text_line();
        }
        else
        {
            while (next_top_line != Text_line_num)
                decr_text_line();
        }

        write_screen(Text_line, Text_line_num);

        // reset editor
        int j = Top;
        while (j != Lin)
        {
            if (Text_line_num == Last_line_num)
            {
                Lin = j;
                break;
            }
            else
            {
                incr_text_line();
                j++;
            }
        }
        gotoxy(Col, Lin);
    }
}

/*
 *   "goto_end_of_file" sets the editor to the end of the file
 *
 *   returns:  nothing
 */
void goto_end_of_file()
{
    // find text line which is to be at top of text screen
    int next_top_line = Last_line_num - 20;
    if (next_top_line < 1)
        next_top_line = 1;

    if (next_top_line > Text_line_num)
    {
        while (next_top_line != Text_line_num)
            incr_text_line();
    }
    else
    {
        while (next_top_line != Text_line_num)
            decr_text_line();
    }

    write_screen(Text_line, Text_line_num);

    // reset editor
    Lin = Top;
    Col = Left;
    gotoxy(Col, Lin);
}

/*
 *   "goto_start_of_file" sets editor to the beginning of the file
 *
 *   returns:  nothing
 */
void goto_start_of_file()
{
    first_text_line();
    write_screen(Text_line, Text_line_num);

    // reset editor
    Lin = Top;
    Col = Left;
    gotoxy(Col, Lin);
}

/*
 *   "write_line" refreshes a text line by clearing the entire line
 *   and then re-writing it
 *
 *   returns:  nothing
 */
void write_line(struct line *text_line,             // text line to write
                int text_line_num,                  // text line number
                int screen_line)                    // screen line of text
{
    char buffer[MAX_LINE_LENGTH];
    int begin_line, begin_char;
    int end_line, end_char, i;

    _setcursortype(_NOCURSOR);
    gotoxy(Left, screen_line);                      // left edge of window
    clreol();
    strcpy(buffer, text_line->string);
    buffer[Right - Left] = NULL;                    // keep line in window

    if (Select_text == true)
    {
        begin_line = Select_begin.line_num;
        begin_char = Select_begin.char_num;

        end_line = Select_end.line_num;
        end_char = Select_end.char_num;

        if ((begin_line < text_line_num)&&(end_line > text_line_num))
        {
            textattr(LIGHTGRAY*16 + BLACK);
            cputs(buffer);
        }
        else if ((begin_line == text_line_num)&&(end_line == text_line_num))
        {
            cputs(buffer);
            textattr(LIGHTGRAY*16 + BLACK);
            gotoxy(begin_char + 1, screen_line);
            for (i = begin_char; i < end_char; i++)
                putch(text_line->string[i]);
        }
        else if (begin_line == text_line_num)
        {
            cputs(buffer);
            textattr(LIGHTGRAY*16 + BLACK);
            gotoxy(begin_char + 1, screen_line);
            for (i = begin_char; i < Right; i++)
            {
                if (text_line->string[i] == NULL)
                    break;
                putch(text_line->string[i]);
            }
        }
        else if (end_line == text_line_num)
        {
            cputs(buffer);
            textattr(LIGHTGRAY*16 + BLACK);
            gotoxy(Left, screen_line);
            for (i = Left - 1; i < end_char; i++)
                putch(text_line->string[i]);
        }
        else
            cputs(buffer);

        textattr(BLACK*16 + WHITE);
    }
    else
        cputs(buffer);

    if (Insert)
        _setcursortype(_NORMALCURSOR);
    else
        _setcursortype(_SOLIDCURSOR);
}

/*
 *   "save_screen" saves the screen to a disk file
 *
 *   returns:  nothing
 */
void save_screen()
{
    char buffer[4000];

    FILE *save = fopen("screen.txt", "w");
    if (save)
    {
        gettext(1, 1, 80, 25, buffer);

        for (int j = 0; j < 25; j++)
        {
            for (int i = 0; i < 80; i++)
                fputc(buffer[160*j + 2*i], save);

            fputc('\n', save);
        }
        fclose(save);
    }

    gotoxy(Col, Lin);                               // reset cursor
}

/*
 *   "write_screen" refreshes the screen by clearing each text line
 *   and then re-writing it
 *
 *   returns:  nothing
 */
void write_screen(struct line *text_line,           // line at top of screen
                  int text_line_num)                // text line number
{
    int j = Top;                                    // from the top
    while (j <= Bottom)                             // write new text lines
    {
        write_line(text_line, text_line_num, j);

        if (text_line_num < Last_line_num)
        {
            text_line = text_line->next;
            text_line_num++;
            j++;
        }
        else
            break;
    }

    j++;
    while (j <= Bottom)                             // clear the rest
    {
        gotoxy(Left, j);
        clreol();
        j++;
    }
}

/*
 *   "select_text" sets or resets the location of the beginning or
 *   ending of a selected region of text
 *
 *   returns:  nothing
 */
void select_text(unsigned char key)                 // Ctrl + key
{
    switch (key)
    {
    case  2: /* Ctrl+B */
        Select_begin.line_ptr = Text_line;
        Select_begin.line_num = Text_line_num;
        Select_begin.char_num = Col - 1;
        break;

    case  5: /* Ctrl+E */
        Select_end.line_ptr = Text_line;
        Select_end.line_num = Text_line_num;
        Select_end.char_num = Col - 1;
        break;

    case 18: /* Ctrl+R */
        Select_begin.line_ptr = NULL;
        Select_begin.line_num = 0;
        Select_begin.char_num = 0;
        Select_end.line_ptr = NULL;
        Select_end.line_num = 0;
        Select_end.char_num = 0;
        break;

    default:
        assert(0);
        break;
    }

    // check for valid select region
    if ((Select_begin.line_ptr == NULL) ||
        (Select_end.line_ptr   == NULL))
        Select_text = false;
    else if (Select_begin.line_num < Select_end.line_num)
        Select_text = true;
    else if ((Select_begin.line_num == Select_end.line_num) &&
             (Select_begin.char_num <  Select_end.char_num))
        Select_text = true;
   else
        Select_text = false;

    // rewrite the text screen
    int text_num = Text_line_num;
    line *text = Text_line;

    int j = Lin;
    while (j != Top)                                // find top text line
    {
        text = text->prev;
        text_num--;
        j--;
    }

    write_screen(text, text_num);
    gotoxy(Col, Lin);
}

/*
 *   "copy_text" clears the previous clipboard and copies a selected
 *   region of text to the clipboard
 *
 *   returns:  nothing
 */
void copy_text()
{
    int begin_char, end_char;

    // make new clipboard
    FILE *clip = fopen("clip.txt", "w");
    if (clip == NULL)
    {
        gettext(1, 1, 80, 25, Screen_buffer);
        error_message("no clipboard");
        get_key();
        restore_edit_window();
        return;
    }

    line *text = Select_begin.line_ptr;
    for (int i = Select_begin.line_num; i <= Select_end.line_num; i++)
    {
        if (text == Select_begin.line_ptr)
            begin_char = Select_begin.char_num;
        else
            begin_char = 0;

        if (text == Select_end.line_ptr)
            end_char = Select_end.char_num;
        else
            end_char = MAX_LINE_LENGTH - 1;

        for (int j = begin_char; j < end_char; j++)
        {
            fputc(text->string[j], clip);
            if (text->string[j] == NULL)
            {
                fputc('\n', clip);
                break;
            }
        }

        if (i < Select_end.line_num)
            text = text->next;
    }
    fclose(clip);
}

/*
 *   "delete_text" deletes a selected region of text
 *
 *   returns:  nothing
 */
void delete_text()
{
    int begin_char, end_char;
    line *text = Select_begin.line_ptr;

    for (int i = Select_begin.line_num; i <= Select_end.line_num; i++)
    {
        if (text == Select_begin.line_ptr)
            begin_char = Select_begin.char_num;
        else
            begin_char = 0;

        if (text == Select_end.line_ptr)
            end_char = Select_end.char_num;
        else
            end_char = MAX_LINE_LENGTH - 1;

        for (int j = begin_char; j < end_char; j++)
        {
            int k = begin_char;
            while (k < MAX_LINE_LENGTH)
            {
                text->string[k] = text->string[k + 1];
                if (text->string[k] == NULL)
                    break;
                k++;
            }
        }
        text = text->next;
    }

    // clear select locators and re-write the text screen
    select_text(18);                                // Ctrl + R
}

/*
 *   "paste_text" copies a selected region of text on the clipboard
 *   to the current cursor location
 *
 *   returns:  nothing
 */
void paste_text()
{
    // open clipboard
    FILE *clip = fopen("clip.txt", "r");
    if (clip == NULL)
    {
        gettext(1, 1, 80, 25, Screen_buffer);
        error_message("no clipboard");
        get_key();
        restore_edit_window();
        return;
    }

    select_text(18);                                // clear select pointers
    select_text(2);                                 // set new begin

    int n = fgetc(clip);
    while (EOF != n)
    {
        char ch = (char) n;

        if (ch == '\n')
            enter_line();
        else
            insert_character(ch);

        n = fgetc(clip);
    }

    select_text(5);                                 // set new end
    fclose(clip);
}

| home | contents | previous | next page | send comment | send link | add bookmark |

Copyright © 2004, Stephen R. Schmitt