home *** CD-ROM | disk | FTP | other *** search
/ Media Share 9 / MEDIASHARE_09.ISO / progmisc / tde221.zip / ED.C < prev    next >
C/C++ Source or Header  |  1993-04-01  |  68KB  |  2,248 lines

  1. /*******************  start of original comments  ********************/
  2. /*
  3.  * Written by Douglas Thomson (1989/1990)
  4.  *
  5.  * This source code is released into the public domain.
  6.  */
  7.  
  8. /*
  9.  * Name:    dte - Doug's Text Editor program - main editor module
  10.  * Purpose: This file contains the main editor module, and a number of the
  11.  *           smaller miscellaneous editing commands.
  12.  *          It also contains the code for dispatching commands.
  13.  * File:    ed.c
  14.  * Author:  Douglas Thomson
  15.  * System:  this file is intended to be system-independent
  16.  * Date:    October 1, 1989
  17.  * I/O:     file being edited
  18.  *          files read or written
  19.  *          user commands and prompts
  20.  * Notes:   see the file "dte.doc" for general program documentation
  21.  */
  22. /*********************  end of original comments   ********************/
  23.  
  24. /*
  25.  * The basic editor routines have been EXTENSIVELY rewritten.  I have added
  26.  * support for lines longer than 80 columns and I have added line number
  27.  * support.  I like to know the real line number that editor functions are
  28.  * working on and I like to know the total number of lines in a file.
  29.  *
  30.  * I rewrote the big series of ifs in the dispatch subroutine.  It is now
  31.  * an array of pointers to functions.  We know what function to call as soon
  32.  * as a key is pressed.  It is also makes it easier to implement a configuration
  33.  * utility and macros.
  34.  *
  35.  * I added a few functions that I use quite often and I deleted a few that I
  36.  * rarely use.  Added are Split Line, Join Line, and Duplicate Line.  Deleted
  37.  * are Goto Marker 0-9 (others?).
  38.  *
  39.  * ************ In TDE 1.3, I put Goto Marker 0-9 back in.  ***************
  40.  *
  41.  * I felt that the insert routine should be separated into two routines.  One
  42.  * for inserting the various combinations of newlines and one for inserting
  43.  * ASCII and extended ASCII characters.
  44.  *
  45.  * One of Doug's design considerations was keeping screen updates to a minimum.
  46.  * I have expanded upon that idea and added support for updating windows
  47.  * LOCALly, GLOBALly, or NOT_LOCALly.  For example, scrolling in one window
  48.  * does not affect the text in another window - LOCAL update.  Adding, deleting,
  49.  * or modifying text in one window may affect text in other windows - GLOBAL
  50.  * update.  Sometimes, updates to the current window are handled in the task
  51.  * routines so updates to other windows are done NOT_LOCALly.
  52.  *
  53.  * In version 2.2, the big text buffer scheme was replaced by a double
  54.  *  linked list.
  55.  *
  56.  * New editor name:  TDE, the Thomson-Davis Editor.
  57.  * Author:           Frank Davis
  58.  * Date:             June 5, 1991, version 1.0
  59.  * Date:             July 29, 1991, version 1.1
  60.  * Date:             October 5, 1991, version 1.2
  61.  * Date:             January 20, 1992, version 1.3
  62.  * Date:             February 17, 1992, version 1.4
  63.  * Date:             April 1, 1992, version 1.5
  64.  * Date:             June 5, 1992, version 2.0
  65.  * Date:             October 31, 1992, version 2.1
  66.  * Date:             April 1, 1993, version 2.2
  67.  *
  68.  * This modification of Douglas Thomson's code is released into the
  69.  * public domain, Frank Davis.   You may distribute it freely.
  70.  */
  71.  
  72. #include "tdestr.h"     /* typedefs for global variables */
  73. #include "define.h"     /* editor function defs */
  74. #include "tdefunc.h"    /* prototypes for all functions in tde */
  75. #include "global.h"     /* global variables */
  76. #include "prompts.h"    /* prompt assignments */
  77. #include "default.h"    /* default function key assignments */
  78.  
  79.  
  80. /*
  81.  * Name:    insert_newline
  82.  * Purpose: insert a newline
  83.  * Date:    June 5, 1991
  84.  * Passed:  window:  pointer to current window
  85.  * Notes:   There a several ways to insert a line into a file:  1) pressing
  86.  *          a key, 2) word wrap, 3) any others?
  87.  *          When doing word wrap or format paragraph, don't show any changes.
  88.  *            Wait until the function finishes then show all changes at once.
  89.  */
  90. int  insert_newline( WINDOW *window )
  91. {
  92. char *source;           /* source for block move to make room for c */
  93. char *dest;             /* destination for block move */
  94. int  len;               /* length of current line */
  95. int  split_len;
  96. int  add;               /* characters to be added (usually 1 in insert mode) */
  97. int  rcol;
  98. int  rc;
  99. long length;
  100. int  carriage_return;
  101. int  split_line;
  102. int  wordwrap;
  103. int  dirty;
  104. int  old_bcol;
  105. register WINDOW *win;   /* put window pointer in a register */
  106. file_infos *file;       /* pointer to file structure in current window */
  107. line_list_ptr new_node;
  108. text_ptr new_line;      /* new line */
  109.  
  110.    rc = OK;
  111.    win = window;
  112.    file = win->file_info;
  113.    length = file->length;
  114.    wordwrap = mode.word_wrap;
  115.    switch (g_status.command) {
  116.       case WordWrap :
  117.          carriage_return = TRUE;
  118.          split_line = FALSE;
  119.          break;
  120.       case AddLine  :
  121.          split_line = carriage_return = FALSE;
  122.          break;
  123.       case SplitLine :
  124.          split_line = carriage_return = TRUE;
  125.          break;
  126.       case Rturn :
  127.       default    :
  128.  
  129.          /*
  130.           * if file is opened in BINARY mode, lets keep the user from
  131.           *   unintentially inserting a line feed into the text.
  132.           */
  133.          if (file->crlf == BINARY)
  134.             return( next_line( win ) );
  135.  
  136.          show_ruler_char( win );
  137.          carriage_return = TRUE;
  138.          split_line = FALSE;
  139.          break;
  140.    }
  141.  
  142.    /*
  143.     * make window temporarily invisible to the un_copy_line function
  144.     */
  145.    new_node = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  146.    new_line = NULL;
  147.    win->visible = FALSE;
  148.    old_bcol = win->bcol;
  149.    if (rc == OK) {
  150.       new_node->line  = new_line;
  151.       new_node->len   = 0;
  152.       new_node->dirty = FALSE;
  153.  
  154.       if (win->ll->len != EOF) {
  155.          win->file_info->modified = TRUE;
  156.          if (mode.do_backups == TRUE)
  157.             rc = backup_file( win );
  158.          copy_line( win->ll );
  159.          detab_linebuff( );
  160.          len = g_status.line_buff_len;
  161.          split_len = 0;
  162.          if (win->rcol < len)
  163.             win->ll->dirty = TRUE;
  164.  
  165.          source = g_status.line_buff + len;
  166.          if (carriage_return || split_line) {
  167.             if (win->rcol < len) {
  168.                source = g_status.line_buff + win->rcol;
  169.                split_len = len - win->rcol;
  170.                len = win->rcol;
  171.             }
  172.          }
  173.          g_status.line_buff_len = len;
  174.          entab_linebuff( );
  175.          if (un_copy_line( win->ll, win, TRUE ) == OK) {
  176.  
  177.             assert( split_len >= 0 );
  178.             assert( split_len < MAX_LINE_LENGTH );
  179.  
  180.             memmove( g_status.line_buff, source, split_len );
  181.             g_status.line_buff_len = len = split_len;
  182.             g_status.copied = TRUE;
  183.             entab_linebuff( );
  184.          } else
  185.             rc = ERROR;
  186.       } else {
  187.          g_status.line_buff_len = len = 0;
  188.          g_status.copied = TRUE;
  189.       }
  190.  
  191.       if (rc == OK) {
  192.          new_node->line  = new_line;
  193.          new_node->len   = 0;
  194.          new_node->dirty = TRUE;
  195.  
  196.          /*
  197.           * we are somewhere in the list and we need to insert the new node.
  198.           *  if we are anywhere except the EOF node, insert the new node
  199.           *  after the current node.  if the current node is the EOF node,
  200.           *  insert the new node before the EOF node.  this keeps the
  201.           *  EOF node at the end of the list.
  202.           */
  203.          if (win->ll->next != NULL) {
  204.             win->ll->next->prev = new_node;
  205.             new_node->next = win->ll->next;
  206.             win->ll->next = new_node;
  207.             new_node->prev = win->ll;
  208.          } else {
  209.             new_node->next = win->ll;
  210.             if (win->ll->prev != NULL)
  211.                win->ll->prev->next = new_node;
  212.             new_node->prev = win->ll->prev;
  213.             win->ll->prev = new_node;
  214.             if (new_node->prev == NULL)
  215.                win->file_info->line_list = new_node;
  216.             win->ll = new_node;
  217.          }
  218.  
  219.          ++file->length;
  220.          detab_linebuff( );
  221.          entab_linebuff( );
  222.          rc = un_copy_line( new_node, win, FALSE );
  223.          adjust_windows_cursor( win, 1 );
  224.  
  225.          file->dirty = NOT_LOCAL;
  226.          if (length == 0l || wordwrap || win->cline == win->bottom_line)
  227.             file->dirty = GLOBAL;
  228.          else if (!split_line)
  229.             update_line( win );
  230.  
  231.          /*
  232.           * If the cursor is to move down to the next line, then update
  233.           *  the line and column appropriately.
  234.           */
  235.          if (rc == OK  &&  (carriage_return || split_line)) {
  236.             dirty = file->dirty;
  237.             if (win->cline < win->bottom_line)
  238.                win->cline++;
  239.             win->rline++;
  240.             if (win->ll->next != NULL) {
  241.                win->bin_offset += win->ll->len;
  242.                win->ll = win->ll->next;
  243.             }
  244.             rcol = win->rcol;
  245.             old_bcol = win->bcol;
  246.  
  247.             if (win->ll->next != NULL) {
  248.                if (mode.indent || wordwrap) {
  249.                   /*
  250.                    * autoindentation is required. Match the indentation of
  251.                    *  the first line above that is not blank.
  252.                    */
  253.                   add = find_left_margin( wordwrap == FIXED_WRAP ?
  254.                                           win->ll : win->ll->prev, wordwrap );
  255.  
  256.                   assert( add >= 0 );
  257.                   assert( add < MAX_LINE_LENGTH );
  258.  
  259.                   copy_line( win->ll );
  260.                   detab_linebuff( );
  261.                   len = g_status.line_buff_len;
  262.                   source = g_status.line_buff;
  263.                   if (len + add > MAX_LINE_LENGTH)
  264.                      add = MAX_LINE_LENGTH - len;
  265.                   dest = source + add;
  266.  
  267.                   assert( len >= 0);
  268.                   assert( len < MAX_LINE_LENGTH );
  269.  
  270.                   memmove( dest, source, len );
  271.  
  272.                   /*
  273.                    * now put in the autoindent characters
  274.                    */
  275.  
  276.                   assert( add >= 0 );
  277.                   assert( add < MAX_LINE_LENGTH );
  278.  
  279.                   memset( source, ' ', add );
  280.                   win->rcol = add;
  281.                   g_status.line_buff_len += add;
  282.                   entab_linebuff( );
  283.                   rc = un_copy_line( win->ll, win, TRUE );
  284.                } else
  285.                   win->rcol = 0;
  286.             }
  287.             if (rc == OK  &&  split_line) {
  288.                win->rline--;
  289.                win->ll = win->ll->prev;
  290.                if (win->cline > win->top_line + window->ruler)
  291.                   win->cline--;
  292.                win->rcol = rcol;
  293.             }
  294.             check_virtual_col( win, win->rcol, win->ccol );
  295.             if (dirty == GLOBAL || file->dirty == LOCAL || wordwrap)
  296.                file->dirty = GLOBAL;
  297.             else
  298.                file->dirty = dirty;
  299.          }
  300.       } else {
  301.          if (new_node != NULL)
  302.             my_free( new_node );
  303.       }
  304.    } else {
  305.       if (new_node != NULL)
  306.          my_free( new_node );
  307.       error( WARNING, window->bottom_line, main4 );
  308.    }
  309.  
  310.    /*
  311.     * record that file has been modified
  312.     */
  313.    win->visible = TRUE;
  314.    if (rc == OK) {
  315.       if (file->dirty != GLOBAL)
  316.          my_scroll_down( win );
  317.       restore_marked_block( win, 1 );
  318.       show_size( win );
  319.       show_avail_mem( );
  320.       if (old_bcol != win->bcol) {
  321.          make_ruler( win );
  322.          show_ruler( win );
  323.       }
  324.    }
  325.    return( rc );
  326. }
  327.  
  328.  
  329. /*
  330.  * Name:    insert_overwrite
  331.  * Purpose: To make the necessary changes after the user has typed a normal
  332.  *           printable character
  333.  * Date:    June 5, 1991
  334.  * Passed:  window:  pointer to current window
  335.  */
  336. int  insert_overwrite( WINDOW *window )
  337. {
  338. char *source;           /* source for block move to make room for c */
  339. char *dest;             /* destination for block move */
  340. int  len;               /* length of current line */
  341. int  pad;               /* padding to add if cursor beyond end of line */
  342. int  add;               /* characters to be added (usually 1 in insert mode) */
  343. register int rcol;
  344. register WINDOW *win;  /* put window pointer in a register */
  345. int  rc;
  346.  
  347.    win = window;
  348.    if (win->ll->len == EOF || g_status.key_pressed >= 256)
  349.       rc = OK;
  350.    else {
  351.       rcol = win->rcol;
  352.       /*
  353.        * first check we have room - the editor can not
  354.        *  cope with lines wider than g_display.line_length
  355.        */
  356.       if (rcol >= g_display.line_length) {
  357.          /*
  358.           * cannot insert more characters
  359.           */
  360.          error( WARNING, win->bottom_line, ed2 );
  361.          rc = ERROR;
  362.       } else {
  363.          copy_line( win->ll );
  364.          detab_linebuff( );
  365.  
  366.          /*
  367.           * work out how many characters need to be inserted
  368.           */
  369.          len = g_status.line_buff_len;
  370.          pad = rcol > len ? rcol - len : 0;
  371.  
  372.          if (mode.insert || rcol >= len)
  373.             /*
  374.              * inserted characters, or overwritten characters at the end of
  375.              *  the line, are inserted.
  376.              */
  377.             add = 1;
  378.          else
  379.             /*
  380.              *  and no extra space is required to overwrite existing characters
  381.              */
  382.             add = 0;
  383.  
  384.          /*
  385.           * check that current line would not get too long.
  386.           */
  387.          if (len + pad + add >= g_display.line_length) {
  388.             /*
  389.              * no more room to add
  390.              */
  391.             error( WARNING, win->bottom_line, ed3 );
  392.             rc = ERROR;
  393.          } else {
  394.  
  395.             /*
  396.              * make room for whatever needs to be inserted
  397.              */
  398.             if (pad > 0  || add > 0) {
  399.                source = g_status.line_buff + rcol - pad;
  400.                dest = source + pad + add;
  401.  
  402.                assert( len + pad - rcol >= 0 );
  403.                assert( len + pad - rcol < MAX_LINE_LENGTH );
  404.  
  405.                memmove( dest, source, len + pad - rcol );
  406.  
  407.                /*
  408.                 * put in the required padding
  409.                 */
  410.  
  411.                assert( pad >= 0 );
  412.                assert( pad < MAX_LINE_LENGTH );
  413.  
  414.                memset( source, ' ', pad );
  415.             }
  416.             g_status.line_buff[rcol] = (char)g_status.key_pressed;
  417.             g_status.line_buff_len += pad + add;
  418.             entab_linebuff( );
  419.  
  420.             /*
  421.              * always increment the real column (rcol) then adjust the
  422.              * logical and base column as needed.   show the changed line
  423.              * in all but the LOCAL window.  In the LOCAL window, there are
  424.              * two cases:  1) update the line, or 2) redraw the window if
  425.              * cursor goes too far right.
  426.              */
  427.             win->file_info->dirty = NOT_LOCAL;
  428.             win->ll->dirty = TRUE;
  429.             show_changed_line( win );
  430.             if (win->ccol < win->end_col) {
  431.                show_curl_line( win );
  432.                show_ruler_char( win );
  433.                win->ccol++;
  434.             } else {
  435.                win->bcol++;
  436.                win->file_info->dirty = LOCAL;
  437.                make_ruler( win );
  438.                show_ruler( win );
  439.             }
  440.             rcol++;
  441.          }
  442.  
  443.          /*
  444.           * record that file has been modified and adjust cursors,
  445.           * file start and end pointers as needed.
  446.           */
  447.          check_virtual_col( win, rcol, win->ccol );
  448.          win->file_info->modified = TRUE;
  449.          if (mode.word_wrap) {
  450.             add = mode.right_justify;
  451.             mode.right_justify = FALSE;
  452.             g_status.command = FormatText;
  453.             word_wrap( win );
  454.             mode.right_justify = add;
  455.          }
  456.          rc = OK;
  457.       }
  458.    }
  459.    return( rc );
  460. }
  461.  
  462.  
  463. /*
  464.  * Name:    join_line
  465.  * Purpose: To join current line and line below at cursor
  466.  * Date:    June 5, 1991
  467.  * Passed:  window:  pointer to current window
  468.  * Notes:   trunc the line.  then, join with line below, if it exists.
  469.  */
  470. int  join_line( WINDOW *window )
  471. {
  472. int  len;               /* length of current line */
  473. int  new_len;           /* length of the joined lines */
  474. int  next_len;          /* length of the line below current line */
  475. text_ptr q;             /* next line in file */
  476. text_ptr tab_free;      /* next line in file -- with the tabs removed */
  477. int  pad;               /* padding spaces required */
  478. register WINDOW *win;   /* put window pointer in a register */
  479. WINDOW *wp;
  480. line_list_ptr next_node;
  481. int  rc;
  482.  
  483.    win = window;
  484.    if (win->ll->len == EOF  ||  win->ll->next->len == EOF)
  485.       return( ERROR );
  486.  
  487.    rc = OK;
  488.  
  489.    assert( win->ll->next != NULL );
  490.  
  491.    next_node = win->ll->next;
  492.    load_undo_buffer( win->file_info, win->ll->line, win->ll->len );
  493.    copy_line( win->ll );
  494.    detab_linebuff( );
  495.  
  496.    /*
  497.     * if cursor is in line before eol, reset len to rcol
  498.     */
  499.    if (win->rcol < (len = g_status.line_buff_len))
  500.       len = win->rcol;
  501.  
  502.    /*
  503.     * calculate needed padding
  504.     */
  505.    pad = win->rcol > len ? win->rcol - len : 0;
  506.  
  507.    assert( pad >= 0 );
  508.    assert( pad < MAX_LINE_LENGTH );
  509.  
  510.    /*
  511.     * if there any tabs in the next line, expand them because we
  512.     *   probably have to redo them anyway.
  513.     */
  514.    next_len = next_node->len;
  515.    tab_free = detab_a_line( next_node->line, &next_len );
  516.  
  517.    assert( next_len >= 0 );
  518.    assert( next_len < MAX_LINE_LENGTH );
  519.    assert( len >= 0 );
  520.    assert( len < MAX_LINE_LENGTH );
  521.  
  522.    /*
  523.     * check room to combine lines
  524.     */
  525.    new_len = len + pad + next_len;
  526.    if (new_len >= g_display.line_length) {
  527.       /*
  528.        * cannot combine lines.
  529.        */
  530.       error( WARNING, win->bottom_line, ed4 );
  531.       rc = ERROR;
  532.    } else {
  533.       if (mode.do_backups == TRUE) {
  534.          win->file_info->modified = TRUE;
  535.          rc = backup_file( win );
  536.       }
  537.       q = (text_ptr)(g_status.line_buff + len);
  538.       /*
  539.        * insert padding
  540.        */
  541.       if (pad > 0) {
  542.          while (pad--)
  543.             *q++ = ' ';
  544.       }
  545.       _fmemcpy( q, tab_free, next_len );
  546.       g_status.line_buff_len = new_len;
  547.       entab_linebuff( );
  548.  
  549.       if ((rc = un_copy_line( win->ll, win, FALSE )) == OK) {
  550.  
  551.          if (next_node->next != NULL)
  552.             next_node->next->prev = win->ll;
  553.          win->ll->next = next_node->next;
  554.          win->ll->dirty = TRUE;
  555.  
  556.          --win->file_info->length;
  557.          ++win->rline;
  558.          adjust_windows_cursor( win, -1 );
  559.          restore_marked_block( win, -1 );
  560.          --win->rline;
  561.  
  562.          wp = g_status.window_list;
  563.          while (wp != NULL) {
  564.             if (wp->file_info == win->file_info) {
  565.                /*
  566.                 * make sure none of the window pointers point to the
  567.                 *   node we are about to delete.
  568.                 */
  569.                if (wp != win) {
  570.                   if (wp->ll == next_node)
  571.                      wp->ll = win->ll->next;
  572.                }
  573.             }
  574.             wp = wp->next;
  575.          }
  576.  
  577.          /*
  578.           * now, it's safe to delete the next_node line as well as
  579.           *   the next node.
  580.           */
  581.          my_free( next_node->line );
  582.          my_free( next_node );
  583.  
  584.          show_size( win );
  585.          show_avail_mem( );
  586.          win->file_info->dirty = GLOBAL;
  587.       }
  588.    }
  589.    return( rc );
  590. }
  591.  
  592.  
  593. /*
  594.  * Name:    word_delete
  595.  * Purpose: To delete from the cursor to the start of the next word.
  596.  * Date:    September 1, 1991
  597.  * Passed:  window:  pointer to current window
  598.  * Notes:   If the cursor is at the right of the line, then combine the
  599.  *           current line with the next one, leaving the cursor where it
  600.  *           is.
  601.  *          If the cursor is on an alphanumeric character, then all
  602.  *           subsequent alphanumeric characters are deleted.
  603.  *          If the cursor is on a space, then all subsequent spaces
  604.  *           are deleted.
  605.  *          If the cursor is on a punctuation character, then all
  606.  *           subsequent punctuation characters are deleted.
  607.  */
  608. int  word_delete( WINDOW *window )
  609. {
  610. int  len;               /* length of current line */
  611. int  count;             /* number of characters deleted from line */
  612. register int start;     /* column that next word starts in */
  613. char *source;           /* source for block move to delete word */
  614. char *dest;             /* destination for block move */
  615. text_ptr p;
  616. register WINDOW *win;   /* put window pointer in a register */
  617. int  rc;
  618.  
  619.    win = window;
  620.    if (win->rline > win->file_info->length  || win->ll->len == EOF)
  621.       return( ERROR );
  622.  
  623.    rc = OK;
  624.    copy_line( win->ll );
  625.    detab_linebuff( );
  626.    if (win->rcol >= (len = g_status.line_buff_len)) {
  627.       rc = join_line( win );
  628.       if (rc == OK) {
  629.          p = win->ll->line;
  630.          if (p != NULL) {
  631.             p += win->rcol;
  632.             if (win->rcol < win->ll->len) {
  633.                len = win->ll->len - win->rcol;
  634.                load_undo_buffer( win->file_info, p, len );
  635.             }
  636.          }
  637.       }
  638.    } else {
  639.  
  640.       assert( len >= 0);
  641.       assert( len < MAX_LINE_LENGTH );
  642.  
  643.       /*
  644.        * normal word delete
  645.        *
  646.        * find the start of the next word
  647.        */
  648.       start = win->rcol;
  649.       if (isspace( g_status.line_buff[start] )) {
  650.          /*
  651.           * the cursor was on a space, so eat all consecutive spaces
  652.           *  from the cursor onwards.
  653.           */
  654.          while (start < len  &&  isspace( g_status.line_buff[start] ))
  655.             ++start;
  656.       } else {
  657.          /*
  658.           * eat all consecutive characters in the same class (spaces
  659.           *  are considered to be in the same class as the cursor
  660.           *  character)
  661.           */
  662.          while (start < len  &&  !isspace( g_status.line_buff[start] ))
  663.             ++start;
  664.          while (start < len  &&  isspace( g_status.line_buff[start] ))
  665.             ++start;
  666.       }
  667.  
  668.       /*
  669.        * move text to delete word
  670.        */
  671.       count = start - win->rcol;
  672.       source = g_status.line_buff + start;
  673.       dest = g_status.line_buff + win->rcol;
  674.  
  675.       assert( len - start >= 0 );
  676.  
  677.       memmove( dest, source, len - start );
  678.       g_status.line_buff_len = len - count;
  679.       entab_linebuff( );
  680.       win->file_info->modified = TRUE;
  681.       win->file_info->dirty = GLOBAL;
  682.       win->ll->dirty = TRUE;
  683.  
  684.       /*
  685.        * word_delete is also called by the word processing functions to get
  686.        *   rid of spaces.
  687.        */
  688.       if (g_status.command == WordDelete)
  689.          show_changed_line( win );
  690.    }
  691.    return( rc );
  692. }
  693.  
  694.  
  695. /*
  696.  * Name:    dup_line
  697.  * Purpose: Duplicate current line
  698.  * Date:    June 5, 1991
  699.  * Passed:  window:  pointer to current window
  700.  * Notes:   cursor stays on current line
  701.  */
  702. int  dup_line( WINDOW *window )
  703. {
  704. register int len;       /* length of current line */
  705. text_ptr p;
  706. register WINDOW *win;   /* put window pointer in a register */
  707. line_list_ptr next_node;
  708. int  rc;
  709.  
  710.    win = window;
  711.  
  712.    /*
  713.     * don't dup a NULL line
  714.     */
  715.    if (win->rline > win->file_info->length  ||  win->ll->len == EOF)
  716.       return( ERROR );
  717.  
  718.    entab_linebuff( );
  719.    rc = un_copy_line( win->ll, win, TRUE );
  720.    len = win->ll->len;
  721.  
  722.    assert( len >= 0);
  723.    assert( len < MAX_LINE_LENGTH );
  724.  
  725.    p = NULL;
  726.    next_node = NULL;
  727.    if (rc == OK) {
  728.       p = (text_ptr)my_malloc( len, &rc );
  729.       next_node = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  730.    }
  731.  
  732.    if (rc == OK) {
  733.       win->file_info->modified = TRUE;
  734.       if (mode.do_backups == TRUE)
  735.          rc = backup_file( win );
  736.       ++win->file_info->length;
  737.  
  738.       if (len > 0)
  739.          _fmemcpy( p, win->ll->line, len );
  740.  
  741.       next_node->line  = p;
  742.       next_node->dirty = TRUE;
  743.       next_node->len   = len;
  744.  
  745.       if (win->ll->next != NULL)
  746.          win->ll->next->prev = next_node;
  747.  
  748.       next_node->next = win->ll->next;
  749.       next_node->prev = win->ll;
  750.       win->ll->next = next_node;
  751.  
  752.       adjust_windows_cursor( win, 1 );
  753.  
  754.       /*
  755.        * if current line is the bottom line, we can't see the dup line because
  756.        * cursor doesn't move and dup line is added after current line.
  757.        */
  758.       if  (win->cline != win->bottom_line)
  759.          my_scroll_down( win );
  760.       win->file_info->dirty = NOT_LOCAL;
  761.  
  762.       /*
  763.        * record that file has been modified
  764.        */
  765.       restore_marked_block( win, 1 );
  766.       show_size( win );
  767.       show_avail_mem( );
  768.    } else {
  769.       /*
  770.        * cannot duplicate line
  771.        */
  772.       if (p != NULL)
  773.          my_free( p );
  774.       if (next_node != NULL)
  775.          my_free( next_node );
  776.       error( WARNING, win->bottom_line, ed5 );
  777.    }
  778.    return( rc );
  779. }
  780.  
  781.  
  782. /*
  783.  * Name:    back_space
  784.  * Purpose: To delete the character to the left of the cursor.
  785.  * Date:    June 5, 1991
  786.  * Passed:  window:  pointer to current window
  787.  * Notes:   If the cursor is at the left of the line, then combine the
  788.  *           current line with the previous one.
  789.  *          If in indent mode, and the cursor is on the first non-blank
  790.  *           character of the line, then match the indentation of an
  791.  *           earlier line.
  792.  */
  793. int  back_space( WINDOW *window )
  794. {
  795. int  rc;                /* return code */
  796. int  len;               /* length of the current line */
  797. char *source;           /* source of block move to delete character */
  798. char *dest;             /* destination of block move */
  799. text_ptr p;             /* previous line in file */
  800. int  plen;              /* length of previous line */
  801. int  del_count;         /* number of characters to delete */
  802. int  pos;               /* the position of the first non-blank char */
  803. register int rcol;
  804. int  ccol;
  805. int  old_bcol;
  806. register WINDOW *win;  /* put window pointer in a register */
  807. WINDOW *wp;
  808. line_list_ptr temp_ll;
  809.  
  810.    win = window;
  811.    if (win->rline > win->file_info->length || win->ll->len == EOF)
  812.       return( ERROR );
  813.    rc = OK;
  814.    copy_line( win->ll );
  815.    detab_linebuff( );
  816.    len = g_status.line_buff_len;
  817.    rcol = win->rcol;
  818.    ccol = win->ccol;
  819.    old_bcol = win->bcol;
  820.    if (rcol == 0) {
  821.       if (win->rline > 1) {
  822.          /*
  823.           * combine this line with the previous, if any
  824.           */
  825.  
  826.          assert( win->ll->prev != NULL );
  827.  
  828.          p = win->ll->prev->line;
  829.          plen = win->ll->prev->len;
  830.          if (len + 2 + plen >= g_display.line_length) {
  831.             /*
  832.              * cannot combine lines
  833.              */
  834.             error( WARNING, win->bottom_line, ed4 );
  835.             return( ERROR );
  836.          }
  837.  
  838.          win->file_info->modified = TRUE;
  839.          if ((rc = un_copy_line( win->ll, win, TRUE )) == OK) {
  840.             --win->rline;
  841.             win->ll = win->ll->prev;
  842.             win->bin_offset -= win->ll->len;
  843.             win->ll->dirty = TRUE;
  844.             copy_line( win->ll );
  845.             detab_linebuff( );
  846.             len = g_status.line_buff_len;
  847.             rcol = len;
  848.  
  849.             p = win->ll->next->line;
  850.             plen = win->ll->next->len;
  851.  
  852.             /*
  853.              * copy previous line into new previous line.
  854.              */
  855.             assert( plen >= 0 );
  856.             assert( len  >= 0 );
  857.  
  858.             _fmemcpy( g_status.line_buff+len, p, plen );
  859.             g_status.line_buff_len = len + plen;
  860.  
  861.             load_undo_buffer( win->file_info, p, plen );
  862.             my_free( p );
  863.  
  864.             temp_ll = win->ll->next;
  865.  
  866.             if (temp_ll->prev != NULL)
  867.                temp_ll->prev->next = temp_ll->next;
  868.             temp_ll->next->prev = temp_ll->prev;
  869.  
  870.             --win->file_info->length;
  871.             ++win->rline;
  872.             restore_marked_block( win, -1 );
  873.             adjust_windows_cursor( win, -1 );
  874.             --win->rline;
  875.  
  876.             wp = g_status.window_list;
  877.             while (wp != NULL) {
  878.                if (wp->file_info == win->file_info) {
  879.                   if (wp != win) {
  880.                      if (wp->ll == temp_ll)
  881.                         wp->ll = win->ll->next;
  882.                   }
  883.                }
  884.                wp = wp->next;
  885.             }
  886.  
  887.             my_free( temp_ll );
  888.  
  889.             if (win->cline > win->top_line + win->ruler)
  890.                --win->cline;
  891.  
  892.             /*
  893.              * make sure cursor stays on the screen, at the end of the
  894.              *  previous line
  895.              */
  896.             ccol = rcol - win->bcol;
  897.             show_size( win );
  898.             show_avail_mem( );
  899.             check_virtual_col( win, rcol, ccol );
  900.             win->file_info->dirty = GLOBAL;
  901.             make_ruler( win );
  902.             show_ruler( win );
  903.          }
  904.       } else
  905.          return( ERROR );
  906.    } else {
  907.       /*
  908.        * normal delete
  909.        *
  910.        * find out how much to delete (depends on indent mode)
  911.        */
  912.       del_count = 1;   /* the default */
  913.       if (mode.indent) {
  914.          /*
  915.           * indent only happens if the cursor is on the first
  916.           *  non-blank character of the line
  917.           */
  918.          pos = first_non_blank( (text_ptr)g_status.line_buff, len );
  919.          if (pos == rcol  ||
  920.                          is_line_blank( (text_ptr)g_status.line_buff, len )) {
  921.             /*
  922.              * now work out how much to indent
  923.              */
  924.             temp_ll = win->ll->prev;
  925.             for (; temp_ll != NULL; temp_ll=temp_ll->prev) {
  926.                p = temp_ll->line;
  927.                plen = first_non_blank( p, temp_ll->len );
  928.                if (plen < rcol  &&  plen != temp_ll->len) {
  929.                   /*
  930.                    * found the line to match
  931.                    */
  932.                   del_count = rcol - plen;
  933.                   break;
  934.                }
  935.             }
  936.          }
  937.       }
  938.  
  939.       /*
  940.        * move text to delete char(s), unless no chars actually there
  941.        */
  942.       if (rcol - del_count < len) {
  943.          dest = g_status.line_buff + rcol - del_count;
  944.          if (rcol > len) {
  945.             source = g_status.line_buff + len;
  946.             pos = 0;
  947.             len = (rcol + 1) - del_count;
  948.          } else {
  949.             source = g_status.line_buff + rcol;
  950.             pos = len - rcol;
  951.             len = len - del_count;
  952.          }
  953.  
  954.          assert( pos >= 0 );
  955.          assert( len >= 0 );
  956.          assert( len <= MAX_LINE_LENGTH );
  957.  
  958.          memmove( dest, source, pos );
  959.          g_status.line_buff_len = len;
  960.          entab_linebuff( );
  961.       }
  962.       rcol -= del_count;
  963.       ccol -= del_count;
  964.       win->file_info->dirty = NOT_LOCAL;
  965.       win->ll->dirty = TRUE;
  966.       show_ruler_char( win );
  967.       show_changed_line( win );
  968.       check_virtual_col( win, rcol, ccol );
  969.       if (!win->file_info->dirty)
  970.          show_curl_line( win );
  971.       if (old_bcol != win->bcol) {
  972.          make_ruler( win );
  973.          show_ruler( win );
  974.       }
  975.    }
  976.    win->file_info->modified = TRUE;
  977.    return( rc );
  978. }
  979.  
  980.  
  981. /*
  982.  * Name:    line_kill
  983.  * Purpose: To delete the line the cursor is on.
  984.  * Date:    June 5, 1991
  985.  * Passed:  window:  pointer to current window
  986.  * Notes:   win->ll->s == NULL then do not do a
  987.  *          line kill (can't kill a NULL line).
  988.  */
  989. int  line_kill( WINDOW *window )
  990. {
  991. register WINDOW *win;   /* put window pointer in a register */
  992. register WINDOW *wp;
  993. line_list_ptr killed_node;
  994. int  rc;
  995.  
  996.    win = window;
  997.    killed_node = win->ll;
  998.    rc = OK;
  999.    if (killed_node->len != EOF) {
  1000.       win->file_info->modified = TRUE;
  1001.       if (mode.do_backups == TRUE)
  1002.          rc = backup_file( win );
  1003.  
  1004.       if (rc == OK) {
  1005.          load_undo_buffer( win->file_info,
  1006.             g_status.copied ? (text_ptr)g_status.line_buff : killed_node->line,
  1007.             g_status.copied ? g_status.line_buff_len       : killed_node->len );
  1008.  
  1009.          --win->file_info->length;
  1010.  
  1011.          win->ll = win->ll->next;
  1012.  
  1013.          if (killed_node->prev != NULL)
  1014.             killed_node->prev->next = killed_node->next;
  1015.          else
  1016.             win->file_info->line_list = win->ll;
  1017.  
  1018.          killed_node->next->prev = killed_node->prev;
  1019.  
  1020.          wp = g_status.window_list;
  1021.          while (wp != NULL) {
  1022.             if (wp->file_info == win->file_info) {
  1023.                if (wp != win) {
  1024.                   if (wp->ll == killed_node)
  1025.                      wp->ll = win->ll;
  1026.                }
  1027.             }
  1028.             wp = wp->next;
  1029.          }
  1030.  
  1031.          /*
  1032.           * free the line and the node
  1033.           */
  1034.          my_free( killed_node->line );
  1035.          my_free( killed_node );
  1036.  
  1037.          win->file_info->dirty = NOT_LOCAL;
  1038.  
  1039.          g_status.copied = FALSE;
  1040.          /*
  1041.           * move all cursors one according to i, restore begin and end block
  1042.           */
  1043.          adjust_windows_cursor( win, -1 );
  1044.          restore_marked_block( win, -1 );
  1045.  
  1046.          /*
  1047.           * we are not doing a GLOBAL update, so update current window here
  1048.           */
  1049.          if (win->file_info->dirty == NOT_LOCAL)
  1050.             my_scroll_down( win );
  1051.          show_size( win );
  1052.          show_avail_mem( );
  1053.       }
  1054.    } else
  1055.       rc = ERROR;
  1056.    return( rc );
  1057. }
  1058.  
  1059.  
  1060. /*
  1061.  * Name:    char_del_under
  1062.  * Purpose: To delete the character under the cursor.
  1063.  * Date:    June 5, 1991
  1064.  * Passed:  window:  pointer to current window
  1065.  * Notes:   If the cursor is beyond the end of the line, then this
  1066.  *           command is ignored.
  1067.  *          DeleteChar and StreamDeleteChar use this function.
  1068.  */
  1069. int  char_del_under( WINDOW *window )
  1070. {
  1071. char *source;    /* source of block move to delete character */
  1072. int  len;
  1073. register WINDOW *win;   /* put window pointer in a register */
  1074.  
  1075.    win = window;
  1076.    if (win->rline > win->file_info->length || win->ll->len == EOF)
  1077.       return( OK );
  1078.    copy_line( win->ll );
  1079.    detab_linebuff( );
  1080.    if (win->rcol < (len = g_status.line_buff_len)) {
  1081.       /*
  1082.        * move text to delete using buffer
  1083.        */
  1084.       source = g_status.line_buff + win->rcol + 1;
  1085.  
  1086.       assert( len - win->rcol >= 0 );
  1087.  
  1088.       memmove( source-1, source, len - win->rcol );
  1089.       --g_status.line_buff_len;
  1090.       entab_linebuff( );
  1091.       win->file_info->dirty    = GLOBAL;
  1092.       win->file_info->modified = TRUE;
  1093.       win->ll->dirty = TRUE;
  1094.       show_changed_line( win );
  1095.    } else if (g_status.command == StreamDeleteChar)
  1096.       join_line( win );
  1097.    return( OK );
  1098. }
  1099.  
  1100.  
  1101. /*
  1102.  * Name:    eol_kill
  1103.  * Purpose: To delete everything from the cursor to the end of the line.
  1104.  * Date:    June 5, 1991
  1105.  * Passed:  window:  pointer to current window
  1106.  * Notes:   If the cursor is beyond the end of the line, then this
  1107.  *           command is ignored.
  1108.  */
  1109. int  eol_kill( WINDOW *window )
  1110. {
  1111. register WINDOW *win;   /* put window pointer in a register */
  1112.  
  1113.    win = window;
  1114.    if (win->rline > win->file_info->length  ||  win->ll->len == EOF)
  1115.       return( OK );
  1116.    copy_line( win->ll );
  1117.    detab_linebuff( );
  1118.    load_undo_buffer( win->file_info, (text_ptr)g_status.line_buff,
  1119.                      g_status.line_buff_len );
  1120.    if (win->rcol < g_status.line_buff_len) {
  1121.       /*
  1122.        * truncate to delete rest of line
  1123.        */
  1124.       g_status.line_buff_len = win->rcol;
  1125.       entab_linebuff( );
  1126.       win->file_info->dirty = GLOBAL;
  1127.       win->ll->dirty = TRUE;
  1128.       show_changed_line( win );
  1129.    }
  1130.    return( OK );
  1131. }
  1132.  
  1133.  
  1134. /*
  1135.  * Name:    undo_line
  1136.  * Purpose: To retrieve unaltered line if possible.
  1137.  * Date:    June 5, 1991
  1138.  * Passed:  window:  pointer to current window
  1139.  * Notes:   Changes are made to the line buffer so the underlying text has
  1140.  *          not changed.  Put the unchanged line from the file into the
  1141.  *          line buffer and display it.
  1142.  */
  1143. int  undo_line( WINDOW *window )
  1144. {
  1145. register WINDOW *win;   /* put window pointer in a register */
  1146.  
  1147.    win = window;
  1148.    if (win->rline <= win->file_info->length  &&  win->ll->len != EOF &&
  1149.                             g_status.copied) {
  1150.       g_status.copied = FALSE;
  1151.       copy_line( win->ll );
  1152.       detab_linebuff( );
  1153.       win->file_info->dirty = GLOBAL;
  1154.       show_changed_line( win );
  1155.    }
  1156.    return( OK );
  1157. }
  1158.  
  1159.  
  1160. /*
  1161.  * Name:    undo
  1162.  * Purpose: To retrieve (pop) a line from the undo stack
  1163.  * Date:    September 26, 1991
  1164.  * Passed:  window:  pointer to current window
  1165.  * Notes:   Insert an empty line into the file then pop the line in the undo
  1166.  *          stack.  When we pop line 0, there are no more lines on the stack.
  1167.  *          Set the stack pointer to -1 to indicate an empty stack.
  1168.  */
  1169. int  undo( WINDOW *window )
  1170. {
  1171. register WINDOW *win;   /* put window pointer in a register */
  1172. line_list_ptr node;
  1173.  
  1174.    win = window;
  1175.    if (win->file_info->undo_count > 0) {
  1176.       entab_linebuff( );
  1177.       if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1178.          return( ERROR );
  1179.  
  1180.       node = win->file_info->undo_top;
  1181.       win->file_info->undo_top = node->next;
  1182.       win->file_info->undo_top->prev = NULL;
  1183.       --win->file_info->undo_count;
  1184.  
  1185.       node->next = node->prev = NULL;
  1186.  
  1187.       ++win->file_info->length;
  1188.  
  1189.       if (win->ll->prev != NULL)
  1190.          win->ll->prev->next = node;
  1191.       node->prev = win->ll->prev;
  1192.  
  1193.       win->ll->prev = node;
  1194.       node->next = win->ll;
  1195.       win->ll = node;
  1196.       win->ll->dirty = TRUE;
  1197.  
  1198.       if (win->ll->prev == NULL)
  1199.          win->file_info->line_list = win->ll;
  1200.  
  1201.       adjust_windows_cursor( win, 1 );
  1202.  
  1203.       /*
  1204.        * we have now undeleted a line.  increment the file length and display
  1205.         * it.
  1206.        */
  1207.       win->file_info->dirty = GLOBAL;
  1208.       show_size( win );
  1209.       show_avail_mem( );
  1210.    }
  1211.    return( OK );
  1212. }
  1213.  
  1214.  
  1215. /*
  1216.  * Name:    beg_next_line
  1217.  * Purpose: To move the cursor to the beginning of the next line.
  1218.  * Date:    October 4, 1991
  1219.  * Passed:  window:  pointer to current window
  1220.  */
  1221. int  beg_next_line( WINDOW *window )
  1222. {
  1223. int  rc;
  1224.  
  1225.    window->rcol = 0;
  1226.    rc = prepare_move_down( window );
  1227.    check_virtual_col( window, window->rcol, window->ccol );
  1228.    sync( window );
  1229.    make_ruler( window );
  1230.    show_ruler( window );
  1231.    return( rc );
  1232. }
  1233.  
  1234.  
  1235. /*
  1236.  * Name:    next_line
  1237.  * Purpose: To move the cursor to the first character of the next line.
  1238.  * Date:    October 4, 1991
  1239.  * Passed:  window:  pointer to current window
  1240.  */
  1241. int  next_line( WINDOW *window )
  1242. {
  1243. register int rcol;
  1244. register WINDOW *win;   /* put window pointer in a register */
  1245. int  rc;
  1246.  
  1247.    win = window;
  1248.    rc = prepare_move_down( win );
  1249.    rcol = first_non_blank( win->ll->line, win->ll->len );
  1250.    check_virtual_col( win, rcol, win->ccol );
  1251.    sync( win );
  1252.    make_ruler( win );
  1253.    show_ruler( win );
  1254.    return( rc );
  1255. }
  1256.  
  1257.  
  1258. /*
  1259.  * Name:    home
  1260.  * Purpose: To move the cursor to the left of the current line.
  1261.  * Date:    June 5, 1991
  1262.  * Passed:  window:  pointer to current window
  1263.  * Notes:   this routine is made a little more complicated with cursor sync.
  1264.  *            if the g_status.copied flag is set we need to see from what file
  1265.  *            the line_buff was copied.
  1266.  */
  1267. int  home( WINDOW *window )
  1268. {
  1269. register int rcol;
  1270. register WINDOW *win;   /* put window pointer in a register */
  1271. text_ptr p;
  1272.  
  1273.    win = window;
  1274.    if (g_status.copied && win->file_info == g_status.current_window->file_info){
  1275.       rcol = first_non_blank( (text_ptr)g_status.line_buff,
  1276.                                         g_status.line_buff_len );
  1277.       if (is_line_blank( (text_ptr)g_status.line_buff, g_status.line_buff_len))
  1278.          rcol = 0;
  1279.    } else {
  1280.       p = win->ll->line;
  1281.       if (p == NULL)
  1282.          rcol = 0;
  1283.       else {
  1284.          rcol = first_non_blank( p, win->ll->len );
  1285.          if (is_line_blank( p, win->ll->len ))
  1286.             rcol = 0;
  1287.       }
  1288.    }
  1289.    if (win->rcol == rcol)
  1290.       rcol = 0;
  1291.    check_virtual_col( win, rcol, win->ccol );
  1292.    sync( win );
  1293.    make_ruler( win );
  1294.    show_ruler( win );
  1295.    return( OK );
  1296. }
  1297.  
  1298.  
  1299. /*
  1300.  * Name:    goto_eol
  1301.  * Purpose: To move the cursor to the eol character of the current line.
  1302.  * Date:    June 5, 1991
  1303.  * Passed:  window:  pointer to current window
  1304.  * Notes:   this routine is made a little more complicated with cursor sync.
  1305.  *            if the g_status.copied flag is set we need to see from what file
  1306.  *            the line_buff was copied.
  1307.  */
  1308. int  goto_eol( WINDOW *window )
  1309. {
  1310. register int rcol;
  1311. register WINDOW *win;   /* put window pointer in a register */
  1312.  
  1313.    win = window;
  1314.    rcol = find_end( win->ll->line, win->ll->len );
  1315.    if (g_status.copied) {
  1316.       if (win->file_info == g_status.current_window->file_info)
  1317.          rcol = find_end( (text_ptr)g_status.line_buff, g_status.line_buff_len);
  1318.    }
  1319.    win->ccol = win->start_col + rcol - win->bcol;
  1320.    check_virtual_col( win, rcol, win->ccol );
  1321.    sync( win );
  1322.    make_ruler( win );
  1323.    show_ruler( win );
  1324.    return( OK );
  1325. }
  1326.  
  1327.  
  1328. /*
  1329.  * Name:    goto_top
  1330.  * Purpose: To move the cursor to the top of the current window.
  1331.  * Date:    June 5, 1991
  1332.  * Passed:  window:  pointer to current window
  1333.  * Notes:   If the start of the file occurs before the top of the window,
  1334.  *           then the start of the file is moved to the top of the window.
  1335.  */
  1336. int  goto_top( WINDOW *window )
  1337. {
  1338. register WINDOW *win;   /* put window pointer in a register */
  1339.  
  1340.    win = window;
  1341.    entab_linebuff( );
  1342.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1343.       return( ERROR );
  1344.    update_line( win );
  1345.    for (; win->cline > win->top_line+win->ruler; win->cline--,win->rline--) {
  1346.       if (win->rline <= 1L)
  1347.          break;
  1348.       else {
  1349.          win->ll = win->ll->prev;
  1350.          win->bin_offset -= win->ll->len;
  1351.       }
  1352.    }
  1353.    show_curl_line( win );
  1354.    sync( win );
  1355.    return( OK );
  1356. }
  1357.  
  1358.  
  1359. /*
  1360.  * Name:    goto_bottom
  1361.  * Purpose: To move the cursor to the bottom of the current window.
  1362.  * Date:    June 5, 1991
  1363.  * Passed:  window:  pointer to current window
  1364.  */
  1365. int  goto_bottom( WINDOW *window )
  1366. {
  1367. register WINDOW *win;   /* put window pointer in a register */
  1368. int  at_top;
  1369.  
  1370.    win = window;
  1371.    entab_linebuff( );
  1372.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1373.       return( ERROR );
  1374.    if (win->ll->len == EOF) {
  1375.       if (win->rline > 1) {
  1376.          at_top = FALSE;
  1377.          if (win->cline == win->top_line + win->ruler) {
  1378.             win->file_info->dirty = LOCAL;
  1379.             at_top = TRUE;
  1380.          }
  1381.          if (!at_top)
  1382.             update_line( win );
  1383.          --win->rline;             /* ALWAYS decrement line counter */
  1384.          win->ll = win->ll->prev;
  1385.          win->bin_offset -= win->ll->len;
  1386.          if (!at_top) {
  1387.             --win->cline;          /* we aren't at top of screen - so move up */
  1388.             show_curl_line( win );
  1389.          }
  1390.       }
  1391.    } else {
  1392.       update_line( win );
  1393.       for (; win->cline < win->bottom_line; win->cline++,win->rline++) {
  1394.          if (win->ll == NULL || win->ll->next == NULL || win->ll->next->len == EOF)
  1395.             break;
  1396.          else {
  1397.             win->bin_offset += win->ll->len;
  1398.             win->ll = win->ll->next;
  1399.          }
  1400.       }
  1401.       show_curl_line( win );
  1402.    }
  1403.    sync( win );
  1404.    return( OK );
  1405. }
  1406.  
  1407.  
  1408. /*
  1409.  * Name:    set_tabstop
  1410.  * Purpose: To set the current interval between tab stops
  1411.  * Date:    October 1, 1989
  1412.  * Notes:   Tab interval must be reasonable, and this function will
  1413.  *           not allow tabs more than MAX_COLS / 2.
  1414.  */
  1415. int  set_tabstop( WINDOW *window )
  1416. {
  1417. char num_str[MAX_COLS]; /* tab interval as a character string */
  1418. int  tab;               /* new tab interval */
  1419. register int rc;
  1420. register file_infos *file;
  1421.  
  1422.    itoa( mode.ltab_size, num_str, 10 );
  1423.    /*
  1424.     * tab interval:
  1425.     */
  1426.    rc = get_name( ed7a, window->bottom_line, num_str, g_display.message_color );
  1427.    if (rc == OK   &&  *num_str != '\0') {
  1428.       tab = atoi( num_str );
  1429.       if (tab < MAX_COLS/2) {
  1430.          mode.ltab_size = tab;
  1431.          if (mode.inflate_tabs) {
  1432.             for (file=g_status.file_list; file != NULL; file=file->next)
  1433.                file->dirty = GLOBAL;
  1434.          }
  1435.       } else {
  1436.          /*
  1437.           * tab size too long
  1438.           */
  1439.          error( WARNING, window->bottom_line, ed8 );
  1440.          rc = ERROR;
  1441.       }
  1442.    }
  1443.  
  1444.    itoa( mode.ptab_size, num_str, 10 );
  1445.    /*
  1446.     * tab interval:
  1447.     */
  1448.    rc = get_name( ed7b, window->bottom_line, num_str, g_display.message_color );
  1449.    if (rc == OK  &&  *num_str != '\0') {
  1450.       tab = atoi( num_str );
  1451.       if (tab < MAX_COLS/2) {
  1452.          mode.ptab_size = tab;
  1453.          show_tab_modes( );
  1454.          if (mode.inflate_tabs) {
  1455.             for (file=g_status.file_list; file != NULL; file=file->next)
  1456.                file->dirty = GLOBAL;
  1457.          }
  1458.       } else {
  1459.          /*
  1460.           * tab size too long
  1461.           */
  1462.          error( WARNING, window->bottom_line, ed8 );
  1463.          rc = ERROR;
  1464.       }
  1465.    }
  1466.    return( rc );
  1467. }
  1468.  
  1469.  
  1470. /*
  1471.  * Name:    show_line_col
  1472.  * Purpose: show current real line and column of current cursor position
  1473.  * Date:    June 5, 1991
  1474.  * Passed:  window:  pointer to current window
  1475.  * Notes:   Blank old position and display new position.  current line and
  1476.  *          column may take up to 12 columns, which allows the display of
  1477.  *          9,999 columns and 9,999,999 lines.
  1478.  */
  1479. void show_line_col( WINDOW *window )
  1480. {
  1481. int  i;
  1482. register int k;
  1483. char line_col[20], num[10];
  1484. char *hex_digit = "0123456789abcdef";
  1485.  
  1486.    /*
  1487.     * blank out current line:column position.
  1488.     */
  1489.    memset( line_col, ' ', 13 );
  1490.    line_col[13] = '\0';
  1491.  
  1492.    /*
  1493.     * convert column to ascii and store in display buffer.
  1494.     */
  1495.    itoa( window->rcol+1, num, 10 );
  1496.    i = strlen( num ) - 1;
  1497.    for (k=12; i>=0; i--, k--)
  1498.       line_col[k] = num[i];
  1499.  
  1500.    /*
  1501.     * put in colon to separate line and column
  1502.     */
  1503.    line_col[k--] = ':';
  1504.  
  1505.    /*
  1506.     * convert line to ascii and store in display buffer.
  1507.     */
  1508.    ltoa( window->rline, num, 10 );
  1509.    i = strlen( num ) - 1;
  1510.    for (; i>=0; i--, k--)
  1511.       line_col[k] = num[i];
  1512.  
  1513.    /*
  1514.     * find line to start line:column display then output
  1515.     */
  1516.    s_output( line_col, window->top_line-1, window->end_col-12,
  1517.              g_display.head_color );
  1518.  
  1519.    strcpy( line_col, " =   " );
  1520.    i = window->rcol;
  1521.    if (g_status.copied) {
  1522.       if (i < g_status.line_buff_len) {
  1523.          k = (int)g_status.line_buff[i];
  1524.          line_col[2] = *(hex_digit + (k >> 4));
  1525.          line_col[3] = *(hex_digit + (k & 0x000f));
  1526.          line_col[4] = 'x';
  1527.          i = TRUE;
  1528.       } else
  1529.          i = FALSE;
  1530.    } else {
  1531.       if (i < window->ll->len) {
  1532.          k = (int)window->ll->line[i];
  1533.          line_col[2] = *(hex_digit + (k >> 4));
  1534.          line_col[3] = *(hex_digit + (k & 0x000f));
  1535.          line_col[4] = 'x';
  1536.          i = TRUE;
  1537.       } else
  1538.          i = FALSE;
  1539.    }
  1540.    s_output( line_col, g_display.mode_line, 58, g_display.mode_color );
  1541.    if (i == TRUE)
  1542.       c_output( k, 58, g_display.mode_line, g_display.mode_color );
  1543.  
  1544.  
  1545.    /*
  1546.     * if file was opened in binary mode, show offset from beginning of file.
  1547.     */
  1548.    if (window->file_info->crlf == BINARY && !window->vertical) {
  1549.       k =  window->ll->line == NULL  ?  0  :  window->rcol;
  1550.       memset( line_col, ' ', 7 );
  1551.       line_col[7] = '\0';
  1552.       s_output( line_col, window->top_line-1, 61, g_display.head_color );
  1553.       ltoa( window->bin_offset + k, line_col, 10 );
  1554.       s_output( line_col, window->top_line-1, 61, g_display.head_color );
  1555.    }
  1556.    show_asterisk( window );
  1557. }
  1558.  
  1559.  
  1560. /*
  1561.  * Name:    show_asterisk
  1562.  * Purpose: give user an indication if file is dirty
  1563.  * Date:    September 16, 1991
  1564.  * Passed:  window:  pointer to current window
  1565.  */
  1566. void show_asterisk( WINDOW *window )
  1567. {
  1568.    c_output( window->file_info->modified ? '*' : ' ', window->start_col+4,
  1569.              window->top_line-1, g_display.head_color );
  1570. }
  1571.  
  1572.  
  1573. /*
  1574.  * Name:    toggle_overwrite
  1575.  * Purpose: toggle overwrite-insert mode
  1576.  * Date:    September 16, 1991
  1577.  * Passed:  arg_filler:  argument to satify function prototype
  1578.  */
  1579. int  toggle_overwrite( WINDOW *arg_filler )
  1580. {
  1581.    mode.insert = !mode.insert;
  1582.    show_insert_mode( );
  1583.    set_cursor_size( mode.insert ? g_display.insert_cursor :
  1584.                     g_display.overw_cursor );
  1585.    return( OK );
  1586. }
  1587.  
  1588.  
  1589. /*
  1590.  * Name:    toggle_smart_tabs
  1591.  * Purpose: toggle smart tab mode
  1592.  * Date:    June 5, 1992
  1593.  * Passed:  arg_filler:  argument to satify function prototype
  1594.  */
  1595. int  toggle_smart_tabs( WINDOW *arg_filler )
  1596. {
  1597.    mode.smart_tab = !mode.smart_tab;
  1598.    show_tab_modes( );
  1599.    return( OK );
  1600. }
  1601.  
  1602.  
  1603. /*
  1604.  * Name:    toggle_indent
  1605.  * Purpose: toggle indent mode
  1606.  * Date:    September 16, 1991
  1607.  * Passed:  arg_filler:  argument to satify function prototype
  1608.  */
  1609. int  toggle_indent( WINDOW *arg_filler )
  1610. {
  1611.    mode.indent = !mode.indent;
  1612.    show_indent_mode( );
  1613.    return( OK );
  1614. }
  1615.  
  1616.  
  1617. /*
  1618.  * Name:    set_left_margin
  1619.  * Purpose: set left margin for word wrap
  1620.  * Date:    November 27, 1991
  1621.  * Passed:  window
  1622.  */
  1623. int  set_left_margin( WINDOW *window )
  1624. {
  1625. register int rc;
  1626. char temp[MAX_COLS];
  1627.  
  1628.    itoa( mode.left_margin + 1, temp, 10 );
  1629.    /*
  1630.     * enter left margin
  1631.     */
  1632.    rc = get_name( ed9, window->bottom_line, temp, g_display.message_color );
  1633.    if (rc == OK  &&  *temp != '\0') {
  1634.       rc = atoi( temp ) - 1;
  1635.       if (rc < 0 || rc >= mode.right_margin) {
  1636.          /*
  1637.           * left margin out of range
  1638.           */
  1639.          error( WARNING, window->bottom_line, ed10 );
  1640.          rc = ERROR;
  1641.       } else {
  1642.          mode.left_margin = rc;
  1643.          show_all_rulers( );
  1644.       }
  1645.    }
  1646.    return( rc );
  1647. }
  1648.  
  1649.  
  1650. /*
  1651.  * Name:    set_right_margin
  1652.  * Purpose: set right margin for word wrap
  1653.  * Date:    November 27, 1991
  1654.  * Passed:  window
  1655.  */
  1656. int  set_right_margin( WINDOW *window )
  1657. {
  1658. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1659. register int rc;
  1660. int  prompt_line;
  1661. char temp[MAX_COLS];
  1662.  
  1663.    prompt_line = window->bottom_line;
  1664.    save_screen_line( 0, prompt_line, line_buff );
  1665.    set_prompt( ed11a, prompt_line );
  1666.    rc = get_yn( );
  1667.    restore_screen_line( 0, prompt_line, line_buff );
  1668.    if (rc != ERROR) {
  1669.       mode.right_justify =  rc == A_YES ? TRUE : FALSE;
  1670.  
  1671.       itoa( mode.right_margin + 1, temp, 10 );
  1672.       /*
  1673.        * enter right margin
  1674.        */
  1675.       rc = get_name( ed11, prompt_line, temp, g_display.message_color );
  1676.       if (rc == OK  &&  *temp != '\0') {
  1677.          rc = atoi( temp ) - 1;
  1678.          if (rc <= mode.left_margin || rc > MAX_LINE_LENGTH) {
  1679.             /*
  1680.              * right margin out of range
  1681.              */
  1682.             error( WARNING, prompt_line, ed12 );
  1683.             rc = ERROR;
  1684.          } else {
  1685.             mode.right_margin = rc;
  1686.             show_all_rulers( );
  1687.          }
  1688.       }
  1689.    }
  1690.    return( rc );
  1691. }
  1692.  
  1693.  
  1694. /*
  1695.  * Name:    set_paragraph_margin
  1696.  * Purpose: set column to begin paragraph
  1697.  * Date:    November 27, 1991
  1698.  * Passed:  window
  1699.  * Notes:   paragraph may be indented, flush, or offset.
  1700.  */
  1701. int  set_paragraph_margin( WINDOW *window )
  1702. {
  1703. register int rc;
  1704. char temp[80];
  1705.  
  1706.    itoa( mode.parg_margin + 1, temp, 10 );
  1707.    /*
  1708.     * enter paragraph margin
  1709.     */
  1710.    rc = get_name( ed13, window->bottom_line, temp, g_display.message_color );
  1711.    if (rc == OK  &&  *temp != '\0') {
  1712.       rc = atoi( temp ) - 1;
  1713.       if (rc < 0 || rc >= mode.right_margin) {
  1714.          /*
  1715.           * paragraph margin out of range
  1716.           */
  1717.          error( WARNING, window->bottom_line, ed14 );
  1718.          rc = ERROR;
  1719.       } else {
  1720.          mode.parg_margin = rc;
  1721.          show_all_rulers( );
  1722.       }
  1723.    }
  1724.    return( rc );
  1725. }
  1726.  
  1727.  
  1728. /*
  1729.  * Name:    toggle_crlf
  1730.  * Purpose: toggle crlf mode
  1731.  * Date:    November 27, 1991
  1732.  * Passed:  arg_filler:  argument to satify function prototype
  1733.  */
  1734. int  toggle_crlf( WINDOW *window )
  1735. {
  1736. register WINDOW *w;
  1737.  
  1738.    ++window->file_info->crlf;
  1739.    if (window->file_info->crlf > BINARY)
  1740.       window->file_info->crlf = CRLF;
  1741.    w = g_status.window_list;
  1742.    while (w != NULL) {
  1743.       if (w->file_info == window->file_info && w->visible )
  1744.          show_crlf_mode( w );
  1745.       w = w->next;
  1746.    }
  1747.    return( OK );
  1748. }
  1749.  
  1750.  
  1751. /*
  1752.  * Name:    toggle_ww
  1753.  * Purpose: toggle word wrap mode
  1754.  * Date:    November 27, 1991
  1755.  * Passed:  arg_filler:  argument to satify function prototype
  1756.  */
  1757. int  toggle_ww( WINDOW *arg_filler )
  1758. {
  1759.    ++mode.word_wrap;
  1760.    if (mode.word_wrap > DYNAMIC_WRAP)
  1761.       mode.word_wrap = NO_WRAP;
  1762.    show_wordwrap_mode( );
  1763.    return( OK );
  1764. }
  1765.  
  1766.  
  1767. /*
  1768.  * Name:    toggle_trailing
  1769.  * Purpose: toggle eleminating trainling space at eol
  1770.  * Date:    November 25, 1991
  1771.  * Passed:  arg_filler:  argument to satify function prototype
  1772.  */
  1773. int  toggle_trailing( WINDOW *arg_filler )
  1774. {
  1775.    mode.trailing = !mode.trailing;
  1776.    show_trailing( );
  1777.    return( OK );
  1778. }
  1779.  
  1780.  
  1781. /*
  1782.  * Name:    toggle_z
  1783.  * Purpose: toggle writing control z at eof
  1784.  * Date:    November 25, 1991
  1785.  * Passed:  arg_filler:  argument to satify function prototype
  1786.  */
  1787. int  toggle_z( WINDOW *arg_filler )
  1788. {
  1789.    mode.control_z = !mode.control_z;
  1790.    show_control_z( );
  1791.    return( OK );
  1792. }
  1793.  
  1794.  
  1795. /*
  1796.  * Name:    toggle_eol
  1797.  * Purpose: toggle writing eol character at eol
  1798.  * Date:    November 25, 1991
  1799.  * Passed:  arg_filler:  argument to satify function prototype
  1800.  */
  1801. int  toggle_eol( WINDOW *arg_filler )
  1802. {
  1803. register file_infos *file;
  1804.  
  1805.    mode.show_eol = !mode.show_eol;
  1806.    for (file=g_status.file_list; file != NULL; file=file->next)
  1807.       file->dirty = GLOBAL;
  1808.    return( OK );
  1809. }
  1810.  
  1811.  
  1812. /*
  1813.  * Name:    toggle_search_case
  1814.  * Purpose: toggle search case
  1815.  * Date:    September 16, 1991
  1816.  * Passed:  arg_filler:  argument to satify function prototype
  1817.  */
  1818. int  toggle_search_case( WINDOW *arg_filler )
  1819. {
  1820.    mode.search_case = (mode.search_case == IGNORE) ? MATCH : IGNORE;
  1821.    show_search_case( );
  1822.    build_boyer_array( );
  1823.    return( OK );
  1824. }
  1825.  
  1826.  
  1827. /*
  1828.  * Name:    toggle_sync
  1829.  * Purpose: toggle sync mode
  1830.  * Date:    January 15, 1992
  1831.  * Passed:  arg_filler:  argument to satify function prototype
  1832.  */
  1833. int  toggle_sync( WINDOW *arg_filler )
  1834. {
  1835.    mode.sync = !mode.sync;
  1836.    show_sync_mode( );
  1837.    return( OK );
  1838. }
  1839.  
  1840.  
  1841. /*
  1842.  * Name:    toggle_ruler
  1843.  * Purpose: toggle ruler
  1844.  * Date:    March 5, 1992
  1845.  * Passed:  arg_filler:  argument to satify function prototype
  1846.  */
  1847. int  toggle_ruler( WINDOW *arg_filler )
  1848. {
  1849. register WINDOW *wp;
  1850.  
  1851.    mode.ruler = !mode.ruler;
  1852.    wp = g_status.window_list;
  1853.    while (wp != NULL) {
  1854.       if (mode.ruler) {
  1855.          /*
  1856.           * there has to be more than one line in a window to display a ruler.
  1857.           *   even if the ruler mode is on, we need to check the num of lines.
  1858.           */
  1859.          if (wp->bottom_line - wp->top_line >0) {
  1860.             if (wp->cline == wp->top_line)
  1861.                ++wp->cline;
  1862.             if (wp->cline > wp->bottom_line)
  1863.                wp->cline = wp->bottom_line;
  1864.             wp->ruler = TRUE;
  1865.          } else
  1866.             wp->ruler = FALSE;
  1867.       } else {
  1868.  
  1869.          /*
  1870.           * if this is the first page in a file, then we may need to "pull"
  1871.           *   the file up before displaying the first page.
  1872.           */
  1873.          if (wp->rline == ((wp->cline - wp->ruler) - (wp->top_line - 1)))
  1874.             --wp->cline;
  1875.          if (wp->cline < wp->top_line)
  1876.             wp->cline = wp->top_line;
  1877.          wp->ruler = FALSE;
  1878.       }
  1879.       make_ruler( wp );
  1880.       setup_window( wp );
  1881.       if (wp->visible)
  1882.          redraw_current_window( wp );
  1883.       wp = wp->next;
  1884.    }
  1885.    return( OK );
  1886. }
  1887.  
  1888.  
  1889. /*
  1890.  * Name:    toggle_tabinflate
  1891.  * Purpose: toggle inflating tabs
  1892.  * Date:    October 31, 1992
  1893.  * Passed:  arg_filler:  argument to satify function prototype
  1894.  */
  1895. int  toggle_tabinflate( WINDOW *arg_filler )
  1896. {
  1897. register file_infos *file;
  1898.  
  1899.    mode.inflate_tabs = !mode.inflate_tabs;
  1900.    for (file=g_status.file_list; file != NULL; file=file->next)
  1901.       file->dirty = GLOBAL;
  1902.    show_tab_modes( );
  1903.    return( OK );
  1904. }
  1905.  
  1906.  
  1907. /*
  1908.  * Name:    sync
  1909.  * Purpose: carry out cursor movements in all visible windows
  1910.  * Date:    January 15, 1992
  1911.  * Passed:  window
  1912.  * Notes:   switch sync semaphore when we do this so we don't get into a
  1913.  *          recursive loop.  all cursor movement commands un_copy_line before
  1914.  *          moving the cursor off the current line.   you MUST make certain
  1915.  *          that the current line is uncopied in the task routines that
  1916.  *          move the cursor off the current line before calling sync.
  1917.  */
  1918. void sync( WINDOW *window )
  1919. {
  1920. register WINDOW *wp;
  1921. register file_infos *fp;
  1922.  
  1923.    if (mode.sync && mode.sync_sem) {
  1924.  
  1925.    /*
  1926.     * these functions must un_copy a line before sync'ing
  1927.     */
  1928. #if defined( __MSC__ )
  1929.       switch (g_status.command) {
  1930.          case  NextLine        :
  1931.          case  BegNextLine     :
  1932.          case  LineDown        :
  1933.          case  LineUp          :
  1934.          case  WordRight       :
  1935.          case  WordLeft        :
  1936.          case  ScreenDown      :
  1937.          case  ScreenUp        :
  1938.          case  EndOfFile       :
  1939.          case  TopOfFile       :
  1940.          case  BotOfScreen     :
  1941.          case  TopOfScreen     :
  1942.          case  JumpToLine      :
  1943.          case  CenterWindow    :
  1944.          case  CenterLine      :
  1945.          case  ScrollDnLine    :
  1946.          case  ScrollUpLine    :
  1947.          case  PanUp           :
  1948.          case  PanDn           :
  1949.          case  NextDirtyLine   :
  1950.          case  PrevDirtyLine   :
  1951.          case  ParenBalance    :
  1952.             assert( g_status.copied == FALSE );
  1953.             break;
  1954.          default  :
  1955.             break;
  1956.       }
  1957. #endif
  1958.  
  1959.       mode.sync_sem = FALSE;
  1960.       for (wp = g_status.window_list;  wp != NULL;  wp = wp->next) {
  1961.          if (wp->visible && wp != window) {
  1962.  
  1963.             /*
  1964.              * when we sync a command, we need to use the same assertions
  1965.              *  as those in editor( ).
  1966.              *
  1967.              * if everything is everything, these core asserts are TRUE.
  1968.              */
  1969. #if defined( __MSC__ )
  1970.             assert( wp != NULL );
  1971.             assert( wp->file_info != NULL );
  1972.             assert( wp->file_info->line_list != NULL );
  1973.             assert( wp->file_info->line_list_end != NULL );
  1974.             assert( wp->file_info->line_list_end->len == EOF );
  1975.             assert( wp->visible == TRUE );
  1976.             assert( wp->rline >= 0 );
  1977.             assert( wp->rline <= wp->file_info->length + 1 );
  1978.             assert( wp->rcol >= 0 );
  1979.             assert( wp->rcol < MAX_LINE_LENGTH );
  1980.             assert( wp->ccol >= wp->start_col );
  1981.             assert( wp->ccol <= wp->end_col );
  1982.             assert( wp->bcol >= 0 );
  1983.             assert( wp->bcol < MAX_LINE_LENGTH );
  1984.             assert( wp->bcol == wp->rcol-(wp->ccol - wp->start_col) );
  1985.             assert( wp->start_col >= 0 );
  1986.             assert( wp->start_col < wp->end_col );
  1987.             assert( wp->end_col < g_display.ncols );
  1988.             assert( wp->cline >= wp->top_line );
  1989.             assert( wp->cline <= wp->bottom_line );
  1990.             assert( wp->top_line > 0 );
  1991.             assert( wp->top_line <= wp->bottom_line );
  1992.             assert( wp->bottom_line < MAX_LINES );
  1993.             assert( wp->bin_offset >= 0 );
  1994.             if (wp->ll->next == NULL)
  1995.                assert( wp->ll->len == EOF );
  1996.             else
  1997.                assert( wp->ll->len >= 0 );
  1998.             assert( wp->ll->len <  MAX_LINE_LENGTH );
  1999. #endif
  2000.  
  2001.             (*do_it[g_status.command])( wp );
  2002.             show_line_col( wp );
  2003.             show_ruler_pointer( wp );
  2004.          }
  2005.       }
  2006.       mode.sync_sem = TRUE;
  2007.       for (fp = g_status.file_list; fp != NULL; fp = fp->next)
  2008.          if (fp->dirty != FALSE)
  2009.             fp->dirty = GLOBAL;
  2010.    }
  2011. }
  2012.  
  2013.  
  2014. /*
  2015.  * Name:    editor
  2016.  * Purpose: Set up the editor structures and display changes as needed.
  2017.  * Date:    June 5, 1991
  2018.  * Notes:   Master editor routine.
  2019.  */
  2020. void editor( )
  2021. {
  2022. char *name;  /* name of file to start editing */
  2023. register WINDOW *window;        /* current active window */
  2024. int  c;
  2025.  
  2026.    /*
  2027.     * initialize search and seize
  2028.     */
  2029.    g_status.sas_defined = FALSE;
  2030.    for (c=0; c<SAS_P; c++)
  2031.       g_status.sas_arg_pointers[c] = NULL;
  2032.  
  2033.    g_status.file_mode = TEXT;
  2034.    /*
  2035.     * Check that user specified file to edit, if not offer help
  2036.     */
  2037.    if (g_status.argc > 1) {
  2038.       c = *g_status.argv[1];
  2039.       if (c == '/'  ||  c == '-') {
  2040.          c = *(g_status.argv[1] + 1);
  2041.          if (c == 'f') {
  2042.             /*
  2043.              * with search and seize their has to be at least 4 arg's, e.g.
  2044.              *    tde -f findme *.c
  2045.              */
  2046.             if (g_status.argc >= 4) {
  2047.                g_status.command = DefineSearchAndSeize;
  2048.  
  2049.                assert( strlen( g_status.argv[2] ) < MAX_COLS );
  2050.  
  2051.                strcpy( (char *)sas_bm.pattern, g_status.argv[2] );
  2052.                for (c=3; c <= g_status.argc; c++)
  2053.                   g_status.sas_arg_pointers[c-3] = g_status.argv[c];
  2054.                g_status.sas_argc = g_status.argc - 3;
  2055.                g_status.sas_arg = 0;
  2056.                g_status.sas_argv = g_status.sas_arg_pointers;
  2057.                g_status.sas_found_first = FALSE;
  2058.                g_status.sas_defined = TRUE;
  2059.                bm.search_defined = sas_bm.search_defined = OK;
  2060.                build_boyer_array( );
  2061.                c = search_and_seize( g_status.current_window );
  2062.             } else
  2063.                c = ERROR;
  2064.          } else if (c == 'b' || c == 'B') {
  2065.             c = atoi( g_status.argv[1] + 2 );
  2066.             if (c <= 0 || c >= MAX_LINE_LENGTH)
  2067.                c = DEFAULT_BIN_LENGTH;
  2068.             ++g_status.arg;
  2069.             g_status.file_mode = BINARY;
  2070.             g_status.file_chunk = c;
  2071.             c = edit_next_file( g_status.current_window );
  2072.          } else
  2073.             c = ERROR;
  2074.       } else
  2075.          c = edit_next_file( g_status.current_window );
  2076.    } else {
  2077.       name = g_status.rw_name;
  2078.       *name = '\0';
  2079.       /*
  2080.        * file name to edit
  2081.        */
  2082.       c = get_name( ed15, g_display.nlines, name, g_display.text_color );
  2083.  
  2084.       assert( strlen( name ) < MAX_COLS );
  2085.  
  2086.       if (c == OK) {
  2087.          if (*name != '\0')
  2088.             c = attempt_edit_display( name, GLOBAL, TEXT, 0 );
  2089.          else
  2090.             c = dir_help( (WINDOW *)NULL );
  2091.       }
  2092.    }
  2093.  
  2094.    g_status.stop =   c == OK  ?  FALSE  :  TRUE;
  2095.    if (c == OK)
  2096.       set_cursor_size( mode.insert ? g_display.insert_cursor :
  2097.                        g_display.overw_cursor );
  2098.  
  2099.    /*
  2100.     * main loop - keep updating the display and processing any commands
  2101.     *  while user has not pressed the stop key
  2102.     */
  2103.    for (; g_status.stop != TRUE;) {
  2104.       window = g_status.current_window;
  2105.  
  2106.  
  2107.       /*
  2108.        * before we do any editor commands, we start out with some basic
  2109.        *   assumptions.
  2110.        *
  2111.        * if everything is everything, these core asserts are TRUE.
  2112.        */
  2113.       assert( window != NULL );
  2114.       assert( window->file_info != NULL );
  2115.       assert( window->file_info->line_list != NULL );
  2116.       assert( window->file_info->line_list_end != NULL );
  2117.       assert( window->file_info->line_list_end->len == EOF );
  2118.       assert( window->visible == TRUE );
  2119.       assert( window->rline >= 0 );
  2120.       assert( window->rline <= window->file_info->length + 1 );
  2121.       assert( window->rcol >= 0 );
  2122.       assert( window->rcol < MAX_LINE_LENGTH );
  2123.       assert( window->ccol >= window->start_col );
  2124.       assert( window->ccol <= window->end_col );
  2125.       assert( window->bcol >= 0 );
  2126.       assert( window->bcol < MAX_LINE_LENGTH );
  2127.       assert( window->bcol == window->rcol-(window->ccol - window->start_col) );
  2128.       assert( window->start_col >= 0 );
  2129.       assert( window->start_col < window->end_col );
  2130.       assert( window->end_col < g_display.ncols );
  2131.       assert( window->cline >= window->top_line );
  2132.       assert( window->cline <= window->bottom_line );
  2133.       assert( window->top_line > 0 );
  2134.       assert( window->top_line <= window->bottom_line );
  2135.       assert( window->bottom_line < MAX_LINES );
  2136.       assert( window->bin_offset >= 0 );
  2137.       if (window->ll->next == NULL)
  2138.          assert( window->ll->len == EOF );
  2139.       else
  2140.          assert( window->ll->len >= 0 );
  2141.       assert( window->ll->len <  MAX_LINE_LENGTH );
  2142.  
  2143.       display_dirty_windows( window );
  2144.  
  2145.       /*
  2146.        * set the critical error handler flag to a known state before we
  2147.        *   do each editor command.
  2148.        */
  2149.       ceh.flag = OK;
  2150.  
  2151. /*
  2152.  * this code is used during testing to check the amount of memory
  2153.  *    in the near heap.
  2154.  *
  2155.  *  ultoa( _fmsize( window->ll ), buff, 10 );
  2156.  *  s_output( "s=       ", g_display.mode_line, 15, g_display.mode_color );
  2157.  *  s_output( buff, g_display.mode_line, 17, g_display.mode_color );
  2158.  */
  2159.  
  2160.       /*
  2161.        * Get a key from the user.  Look up the function assigned to that key.
  2162.        * All regular text keys are assigned to function 0.  Text characters
  2163.        * are less than 0x100, decimal 256, which includes the ASCII and
  2164.        * extended ASCII character set.
  2165.        */
  2166.       g_status.key_pressed = getkey( );
  2167.       g_status.command = getfunc( g_status.key_pressed );
  2168.       if (g_status.wrapped  ||  g_status.key_pending) {
  2169.          g_status.key_pending = FALSE;
  2170.          g_status.wrapped = FALSE;
  2171.          show_search_message( CLR_SEARCH, g_display.mode_color );
  2172.       }
  2173.       g_status.control_break = FALSE;
  2174.       if (g_status.command >= 0 && g_status.command < NUM_FUNCS) {
  2175.          record_keys( window->bottom_line );
  2176.          (*do_it[g_status.command])( window );
  2177.       }
  2178.    }
  2179.    cls( );
  2180.    xygoto( 0, 0 );
  2181. }
  2182.  
  2183.  
  2184. /*
  2185.  * Name:    display_dirty_windows
  2186.  * Purpose: Set up the editor structures and display changes as needed.
  2187.  * Date:    June 5, 1991
  2188.  * Notes:   Display all windows with dirty files.
  2189.  */
  2190. void display_dirty_windows( WINDOW *window )
  2191. {
  2192. register WINDOW *below;         /* window below current */
  2193. register WINDOW *above;         /* window above current */
  2194. file_infos *file;               /* temporary file structure */
  2195.  
  2196.    /*
  2197.     * update all windows that point to any file that has been changed
  2198.     */
  2199.    above = below = window;
  2200.    while (above->prev || below->next) {
  2201.       if (above->prev) {
  2202.          above = above->prev;
  2203.          show_dirty_window( above );
  2204.       }
  2205.       if (below->next) {
  2206.          below = below->next;
  2207.          show_dirty_window( below );
  2208.       }
  2209.    }
  2210.    file = window->file_info;
  2211.    if (file->dirty == LOCAL || file->dirty == GLOBAL)
  2212.       display_current_window( window );
  2213.    for (file=g_status.file_list; file != NULL; file=file->next)
  2214.       file->dirty = FALSE;
  2215.  
  2216.    /*
  2217.     * Set the cursor position at window->ccol, window->cline.  Show the
  2218.     * user where in the file the cursor is positioned.
  2219.     */
  2220.    xygoto( window->ccol, window->cline );
  2221.    show_line_col( window );
  2222.    show_ruler_pointer( window );
  2223. }
  2224.  
  2225.  
  2226.  
  2227. /*
  2228.  * Name:    show_dirty_window
  2229.  * Purpose: show changes in non-current window
  2230.  * Date:    June 5, 1991
  2231.  * Passed:  window:  pointer to current window
  2232.  */
  2233. void show_dirty_window( WINDOW *window )
  2234. {
  2235. register WINDOW *win;   /* register window pointer */
  2236. int  dirty;
  2237.  
  2238.   win = window;
  2239.   if (win->visible) {
  2240.      dirty = win->file_info->dirty;
  2241.      if (dirty == GLOBAL || dirty == NOT_LOCAL) {
  2242.         display_current_window( win );
  2243.         show_size( win );
  2244.      }
  2245.      show_asterisk( win );
  2246.   }
  2247. }
  2248.