home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / editors / tde150.arj / WINDOW.C < prev    next >
C/C++ Source or Header  |  1992-04-01  |  44KB  |  1,379 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 - window module
  10.  * Purpose: This file contains the code associated with opening and sizing
  11.  *           windows, and also displaying the help window.
  12.  * File:    window.c
  13.  * Author:  Douglas Thomson
  14.  * System:  this file is intended to be system-independent
  15.  * Date:    October 12, 1989
  16.  */
  17. /*********************  end of original comments   ********************/
  18.  
  19.  
  20. /*
  21.  * The window routines have been EXTENSIVELY rewritten.  Some routines were
  22.  * changed so only one logical function is carried out, eg. 'initialize_window'.
  23.  * I like the Microsoft way of resizing windows - just press the up and down
  24.  * arrows to adjust the window to desired size.  I also like pressing one key
  25.  * to change windows.  All of which are implemented.
  26.  *
  27.  * In tde, version 1.4, I added support for vertical windows.
  28.  *
  29.  * New editor name:  tde, the Thomson-Davis Editor.
  30.  * Author:           Frank Davis
  31.  * Date:             June 5, 1991, version 1.0
  32.  * Date:             July 29, 1991, version 1.1
  33.  * Date:             October 5, 1991, version 1.2
  34.  * Date:             January 20, 1992, version 1.3
  35.  * Date:             February 17, 1992, version 1.4
  36.  * Date:             April 1, 1992, version 1.5
  37.  *
  38.  * This modification of Douglas Thomson's code is released into the
  39.  * public domain, Frank Davis.  You may distribute it freely.
  40.  */
  41.  
  42. #include "tdestr.h"
  43. #include "common.h"
  44. #include "define.h"
  45. #include "tdefunc.h"
  46.  
  47.  
  48. /*
  49.  * Name:    initialize_window
  50.  * Purpose: To open a new window
  51.  * Date:    June 5, 1991
  52.  * Returns: OK if window opened successfully
  53.  *          ERROR if anything went wrong
  54.  * Notes:   If this is first window then set up as normal displayed window
  55.  *          otherwise make the present window invisible and open a new
  56.  *          window in the same screen location as the old one.
  57.  */
  58. int  initialize_window( void )
  59. {
  60. int top;
  61. int bottom;
  62. int start_col;
  63. int end_col;
  64. WINDOW *wp;        /* used for scanning windows */
  65. WINDOW *window;
  66. register file_infos *fp;     /* used for scanning files */
  67. register int rc;
  68.  
  69.    rc = OK;
  70.    window = g_status.current_window;
  71.    fp = g_status.current_file;
  72.    if (window == NULL) {
  73.       /*
  74.        * special case if this is the first window on screen.
  75.        */
  76.       top = start_col = 0;
  77.       bottom  = g_display.nlines;
  78.       end_col = g_display.ncols - 1;
  79.    } else {
  80.       /*
  81.        * else put the new window in same place as current window.
  82.        * make current window invisible.  new window becomes current window.
  83.        */
  84.       top       = window->top_line - 1;
  85.       bottom    = window->bottom_line;
  86.       start_col = window->start_col;
  87.       end_col   = window->end_col;
  88.    }
  89.  
  90.    if (create_window( &wp, top, bottom, start_col, end_col, fp ) == ERROR) {
  91.       error( WARNING, bottom, "out of memory" );
  92.  
  93.       /*
  94.        * This is a real nuisance. We had room for the file and the
  95.        *  file structure, but not enough for the window as well.
  96.        * Now we must free all the memory that has already been
  97.        *  allocated.
  98.        */
  99.       if (fp->ref_count == 0) {
  100.          if (fp->prev)
  101.             fp->prev->next = fp->next;
  102.          else
  103.             g_status.file_list = fp->next;
  104.          if (fp->next)
  105.             fp->next->prev = fp->prev;
  106.          g_status.end_mem = fp->start_text;
  107.          free( fp );
  108.          wp = g_status.current_window;
  109.          if (wp != NULL && wp->visible)
  110.             g_status.current_file = wp->file_info;
  111.          else
  112.             g_status.stop = TRUE;
  113.       }
  114.       rc = ERROR;
  115.    }
  116.  
  117.    if (rc != ERROR) {
  118.       /*
  119.        * set up the new cursor position as appropriate
  120.        */
  121.       wp->cursor = cpf( fp->start_text );
  122.       wp->ccol = wp->start_col;
  123.       wp->rcol = wp->bcol = 0;
  124.       wp->rline = 1l;
  125.       wp->visible = TRUE;
  126.       wp->letter = fp->next_letter++;
  127.       if (window != NULL)
  128.          window->visible = FALSE;
  129.  
  130.       /*
  131.        * the new window becomes the current window.
  132.        */
  133.       g_status.current_window = wp;
  134.    }
  135.    return( rc );
  136. }
  137.  
  138.  
  139. /*
  140.  * Name:    next_window
  141.  * Purpose: To move to the next visible window.
  142.  * Date:    June 5, 1991
  143.  * Passed:  window:   information allowing access to the current window
  144.  * Notes:   Start with current window.  If next window exists then go to
  145.  *          it else go to the first (top) window on screen.
  146.  *          When I added vertical windows, finding the "correct" next
  147.  *          window became extremely, unnecessarily, unmanageably complicated.
  148.  *          let's just use a simple procedure to find the first available,
  149.  *          visible, next window.
  150.  */
  151. void next_window( WINDOW *window )
  152. {
  153. register WINDOW *wp;
  154. int change;
  155.  
  156.    if (window != NULL) {
  157.       change = FALSE;
  158.       /*
  159.        * start with current window and look for first next
  160.        * visible window
  161.        */
  162.       wp = window->next;
  163.       while (wp != NULL) {
  164.          if (wp->visible) {
  165.             change = TRUE;
  166.             break;
  167.          }
  168.          wp = wp->next;
  169.       }
  170.  
  171.       /*
  172.        * if we haven't found a visible window yet, go to the end of
  173.        * the list and work backwards until we find a visible window.
  174.        */
  175.       if (!change) {
  176.          wp = g_status.window_list;
  177.          while (wp != window) {
  178.             if (wp->visible) {
  179.                change = TRUE;
  180.                break;
  181.             }
  182.             wp = wp->next;
  183.          }
  184.       }
  185.       if (change == TRUE) {
  186.          un_copy_line( window->cursor, window, TRUE );
  187.          g_status.current_window = wp;
  188.          g_status.current_file = wp->file_info;
  189.       }
  190.    }
  191. }
  192.  
  193.  
  194. /*
  195.  * Name:    prev_window
  196.  * Purpose: To move to the previous visible window.
  197.  * Date:    June 5, 1991
  198.  * Passed:  window:   information allowing access to the current window
  199.  * Notes:   Start with current window.  If previous window exists then go to
  200.  *          it else go to the last (bottom) window on screen.  Opposite of
  201.  *          next_window.
  202.  *          when I added vertical windows, finding the "correct" previous
  203.  *          window became extremely, unnecessarily, unmanageably complicated.
  204.  *          let's just use a simple procedure to find the first available,
  205.  *          visible, previous window.
  206.  */
  207. void prev_window( WINDOW *window )
  208. {
  209. register WINDOW *wp;
  210. int change;
  211.  
  212.    if (window != NULL) {
  213.       change = FALSE;
  214.  
  215.       /*
  216.        * start with current window and look for first previous
  217.        * visible window
  218.        */
  219.       wp = window->prev;
  220.       while (wp != NULL) {
  221.          if (wp->visible) {
  222.             change = TRUE;
  223.             break;
  224.          }
  225.          wp = wp->prev;
  226.       }
  227.  
  228.       /*
  229.        * if we haven't found a visible window yet, go to the end of
  230.        * the list and work backwards until we find a visible window.
  231.        */
  232.       if (!change) {
  233.          wp = window->next;
  234.          if (wp != NULL) {
  235.             while (wp->next != NULL)
  236.                wp = wp->next;
  237.             while (wp != window) {
  238.                if (wp->visible) {
  239.                   change = TRUE;
  240.                   break;
  241.                }
  242.                wp = wp->prev;
  243.             }
  244.          }
  245.       }
  246.       if (change == TRUE) {
  247.          un_copy_line( window->cursor, window, TRUE );
  248.          g_status.current_window = wp;
  249.          g_status.current_file = wp->file_info;
  250.       }
  251.    }
  252. }
  253.  
  254.  
  255. /*
  256.  * Name:    split_horizontal
  257.  * Purpose: To split screen horizontally at the cursor.
  258.  * Date:    June 5, 1991
  259.  * Passed:  window:   information allowing access to the current window
  260.  * Notes:   split the screen horizontally at the cursor position.
  261.  */
  262. void split_horizontal( WINDOW *window )
  263. {
  264. register WINDOW *wp;
  265. register WINDOW *win;  /* register pointer for window */
  266. WINDOW *temp;
  267. file_infos *file;       /* file structure for file belonging to new window */
  268.  
  269.    win = window;
  270.    /*
  271.     * check that there is room for the window
  272.     */
  273.    if (win->bottom_line - win->cline < 2)
  274.       error( WARNING, win->bottom_line, "move cursor up first" );
  275.    else {
  276.       file = win->file_info;
  277.       if (create_window( &temp, win->cline+1, win->bottom_line,
  278.                          win->start_col, win->end_col, file ) == ERROR) {
  279.          error( WARNING, win->bottom_line, "out of memory" );
  280.       } else {
  281.          un_copy_line( win->cursor, win, TRUE );
  282.          wp = temp;
  283.          /*
  284.           * record that the current window has lost some lines from
  285.           *  the bottom for the new window, and adjust its page size
  286.           *  etc accordingly.
  287.           */
  288.          win->bottom_line = win->cline;
  289.          setup_window( win );
  290.          display_current_window( win );
  291.  
  292.          /*
  293.           * set up the new cursor position as appropriate
  294.           */
  295.          wp->rcol = win->rcol;
  296.          wp->ccol = win->ccol;
  297.          wp->bcol = win->bcol;
  298.          wp->rline = win->rline;
  299.          wp->cline = wp->cline + win->cline - (win->top_line + win->ruler);
  300.          if (wp->cline > wp->bottom_line)
  301.             wp->cline = wp->bottom_line;
  302.          wp->cursor = win->cursor;
  303.          wp->visible = TRUE;
  304.          wp->vertical = win->vertical;
  305.          wp->letter = file->next_letter++;
  306.          wp->ruler  = mode.ruler;
  307.  
  308.          /*
  309.           * the new window becomes the current window.
  310.           */
  311.          g_status.current_window = wp;
  312.  
  313.          show_window_count( g_status.window_count );
  314.          show_window_header( wp );
  315.          display_current_window( wp );
  316.          if (wp->vertical)
  317.             show_vertical_separator( wp );
  318.          make_ruler( wp );
  319.          show_ruler( wp );
  320.       }
  321.    }
  322. }
  323.  
  324.  
  325. /*
  326.  * Name:    split_vertical
  327.  * Purpose: To split screen vertically at the cursor.
  328.  * Date:    June 5, 1991
  329.  * Passed:  window:   information allowing access to the current window
  330.  * Notes:   split the screen vertically at the cursor position.
  331.  */
  332. void split_vertical( WINDOW *window )
  333. {
  334. register WINDOW *wp;
  335. register WINDOW *win;  /* register pointer for window */
  336. WINDOW *temp;
  337. file_infos *file;       /* file structure for file belonging to new window */
  338.  
  339.    win = window;
  340.    /*
  341.     * check that there is room for the window
  342.     */
  343.    if (win->start_col + 15 > win->ccol)
  344.       error( WARNING, win->bottom_line, "move cursor right first" );
  345.    else if (win->end_col - 15 < win->ccol)
  346.       error( WARNING, win->bottom_line, "move cursor left first" );
  347.    else {
  348.       file = win->file_info;
  349.       if (create_window( &temp, win->top_line-1, win->bottom_line,
  350.                          win->ccol+1, win->end_col, file ) == ERROR) {
  351.          error( WARNING, win->bottom_line, "out of memory" );
  352.       } else {
  353.          un_copy_line( win->cursor, win, TRUE );
  354.          wp = temp;
  355.          /*
  356.           * record that the current window has lost some columns from
  357.           *  the window to the left for the new window
  358.           */
  359.          win->ccol = win->end_col = win->ccol - 1;
  360.          win->rcol--;
  361.          win->vertical = TRUE;
  362.          show_window_header( win );
  363.          show_vertical_separator( win );
  364.          display_current_window( win );
  365.          make_ruler( win );
  366.          show_ruler( win );
  367.          show_ruler_pointer( win );
  368.  
  369.          /*
  370.           * set up the new cursor position as appropriate
  371.           */
  372.          wp->rcol = win->rcol;
  373.          wp->ccol = wp->start_col + win->ccol - win->start_col;
  374.          if (wp->ccol > wp->end_col)
  375.             wp->ccol = wp->end_col;
  376.          wp->bcol = win->bcol;
  377.          wp->rline = win->rline;
  378.          wp->cline = win->cline;
  379.          wp->cursor = win->cursor;
  380.          wp->visible = TRUE;
  381.          wp->vertical = TRUE;
  382.          wp->letter = file->next_letter++;
  383.          wp->ruler  = mode.ruler;
  384.  
  385.          /*
  386.           * the new window becomes the current window.
  387.           */
  388.          g_status.current_window = wp;
  389.  
  390.          check_virtual_col( wp, wp->rcol, wp->ccol );
  391.          wp->file_info->dirty = FALSE;
  392.          show_window_count( g_status.window_count );
  393.          show_window_header( wp );
  394.          display_current_window( wp );
  395.          make_ruler( wp );
  396.          show_ruler( wp );
  397.       }
  398.    }
  399. }
  400.  
  401.  
  402. /*
  403.  * Name:    show_vertical_separator
  404.  * Purpose: To separate vertical screens
  405.  * Date:    June 5, 1991
  406.  * Passed:  window:   information allowing access to the current window
  407.  */
  408. void show_vertical_separator( WINDOW *window )
  409. {
  410. int i;
  411. int line;
  412. int col;
  413.  
  414.    line = window->top_line - 1;
  415.    col  = window->end_col + 1;
  416.    if (col < g_display.ncols - 1) {
  417.       i = window->bottom_line + 1 - line;
  418.       while (i-- > 0)
  419.          c_output( VERTICAL_CHAR, col, line++, g_display.head_color );
  420.    }
  421. }
  422.  
  423.  
  424. /*
  425.  * Name:    size_window
  426.  * Purpose: To change the size of the current and one other window.
  427.  * Date:    June 5, 1991
  428.  * Passed:  window:   information allowing access to the current window
  429.  * Notes:   Use the Up and Down arrow keys to make the current window
  430.  *          bigger or smaller.  The window above will either grow
  431.  *          or contract accordingly.
  432.  */
  433. void size_window( WINDOW *window )
  434. {
  435. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  436. int func, c;
  437. register WINDOW *above;
  438. register WINDOW *win;
  439. int resize;
  440. int show_above_ruler;
  441. char *instr =
  442.        "Press Up or Down to change window size.  Press Return when done.";
  443.  
  444.    win = window;
  445.    if (win->top_line != 1 && !win->vertical) {
  446.       un_copy_line( win->cursor, win, TRUE );
  447.       save_screen_line( 0, win->bottom_line, line_buff );
  448.       set_prompt( instr, win->bottom_line );
  449.  
  450.       /*
  451.        * resizing only affects current window and above visible window
  452.        */
  453.       above = g_status.window_list;
  454.       while (above->bottom_line + 2 != win->top_line || !above->visible)
  455.          above = above->next;
  456.       if (above->vertical)
  457.         error( WARNING, win->bottom_line, "can not resize vertical window" );
  458.       else {
  459.          show_above_ruler = FALSE;
  460.          for (func=0; func != AbortCommand && func != Rturn; ) {
  461.  
  462.             /*
  463.              * If user has redined the ESC and Return keys, make them Rturn and
  464.              * AbortCommand in this function.
  465.              */
  466.             c = getkey( );
  467.             func = getfunc( c );
  468.             if (c == RTURN || func == NextLine || func == BegNextLine)
  469.                func = Rturn;
  470.             else if (c == ESC)
  471.                func = AbortCommand;
  472.             resize = FALSE;
  473.  
  474.             /*
  475.              * if LineUp, make current window top line grow and bottom line
  476.              * of above window shrink.   if window movement covers up current
  477.              * line of window then we must adjust logical line and real line.
  478.              */
  479.             if (func == LineUp) {
  480.                if (above->bottom_line > above->top_line + above->ruler) {
  481.                   if (win->rline == (win->cline - (win->top_line+win->ruler-1)))
  482.                      --win->cline;
  483.                   --win->top_line;
  484.                   if (above->cline == above->bottom_line)
  485.                      --above->cline;
  486.                   --above->bottom_line;
  487.                   resize = TRUE;
  488.                   if (mode.ruler) {
  489.                      if (win->ruler == FALSE) {
  490.                         if (win->cline == win->top_line)
  491.                            ++win->cline;
  492.                         if (win->cline > win->bottom_line)
  493.                            win->cline = win->bottom_line;
  494.                         win->ruler = TRUE;
  495.                      }
  496.                   }
  497.                }
  498.  
  499.             /*
  500.              * if LineDown, make current window top line shrink and bottom line
  501.              * of above window grow.   if window movement covers up current
  502.              * line of window then we must adjust logical line and real line.
  503.              */
  504.             } else if (func == LineDown) {
  505.                if (win->bottom_line > win->top_line + win->ruler) {
  506.                   if (win->cline == win->top_line + win->ruler)
  507.                      ++win->cline;
  508.                   ++win->top_line;
  509.                   ++above->bottom_line;
  510.                   resize = TRUE;
  511.                   if (mode.ruler) {
  512.                      if (above->ruler == FALSE) {
  513.                         if (above->cline == above->top_line)
  514.                            ++above->cline;
  515.                         if (above->cline > above->bottom_line)
  516.                            above->cline = above->bottom_line;
  517.                         above->ruler = TRUE;
  518.                         make_ruler( above );
  519.                         show_above_ruler = TRUE;
  520.                      }
  521.                   }
  522.                }
  523.             }
  524.  
  525.             /*
  526.              * if we resize a window then update window size and current and
  527.              * real lines if needed.
  528.              */
  529.             if (resize == TRUE) {
  530.                setup_window( above );
  531.                display_current_window( above );
  532.                if (show_above_ruler) {
  533.                   show_ruler( above );
  534.                   show_ruler_pointer( above );
  535.                   show_above_ruler = FALSE;
  536.                }
  537.                setup_window( win );
  538.                show_window_header( win );
  539.                win->ruler = mode.ruler;
  540.                make_ruler( win );
  541.                show_ruler( win );
  542.                show_ruler_pointer( win );
  543.                display_current_window( win );
  544.                save_screen_line( 0, win->bottom_line, line_buff );
  545.                set_prompt( instr, win->bottom_line );
  546.             }
  547.          }
  548.       }
  549.       restore_screen_line( 0, win->bottom_line, line_buff );
  550.    } else {
  551.      if (win->vertical)
  552.         error( WARNING, win->bottom_line, "can not resize vertical window" );
  553.      else
  554.         error( WARNING, win->bottom_line, "can not resize top window" );
  555.    }
  556. }
  557.  
  558.  
  559. /*
  560.  * Name:    zoom_window
  561.  * Purpose: To blow-up current window.
  562.  * Date:    September 1, 1991
  563.  * Passed:  window:   information allowing access to the current window
  564.  * Notes:   Make all windows, visible and hidden, full size.
  565.  */
  566. void zoom_window( WINDOW *window )
  567. {
  568. register WINDOW *wp;
  569.  
  570.    if (window != NULL) {
  571.       if (window->top_line != 1 || window->bottom_line != g_display.nlines) {
  572.          un_copy_line( window->cursor, window, TRUE );
  573.          for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  574.             if (wp != window && wp->visible)
  575.                wp->visible = FALSE;
  576.             if (wp->top_line != 1)
  577.                wp->cline = wp->cline - (wp->top_line+wp->ruler) + 1;
  578.             wp->top_line = 1;
  579.             wp->bottom_line = g_display.nlines;
  580.             wp->end_col   = g_display.ncols - 1;
  581.             wp->start_col = 0;
  582.             wp->vertical = FALSE;
  583.             make_ruler( wp );
  584.          }
  585.          redraw_screen( window );
  586.          show_ruler( window );
  587.       }
  588.    }
  589. }
  590.  
  591.  
  592. /*
  593.  * Name:    next_hidden_window
  594.  * Purpose: To display the window that is "behind" current window.
  595.  * Date:    September 1, 1991
  596.  * Passed:  window:   information allowing access to the current window
  597.  */
  598. void next_hidden_window( WINDOW *window )
  599. {
  600. int poof = FALSE;
  601. register WINDOW *wp;
  602.  
  603.    if (window != NULL) {
  604.  
  605.       /*
  606.        * look for next hidden window starting with current window.
  607.        */
  608.       wp = window;
  609.       for (wp=window->next; wp != NULL && !poof; ) {
  610.          if (!wp->visible)
  611.             poof = TRUE;
  612.          else
  613.             wp = wp->next;
  614.       }
  615.  
  616.       /*
  617.        * if we haven't found an invisible window yet, start looking
  618.        * for a hidden window from the beginning of the window list.
  619.        */
  620.       if (!poof) {
  621.          for (wp=g_status.window_list; wp != NULL && !poof; ) {
  622.             if (!wp->visible)
  623.                poof = TRUE;
  624.             else
  625.                wp = wp->next;
  626.          }
  627.       }
  628.  
  629.       if (poof) {
  630.          un_copy_line( window->cursor, window, TRUE );
  631.          wp->cline = window->top_line + window->ruler +
  632.                        (wp->cline - (wp->top_line + wp->ruler));
  633.          wp->top_line = window->top_line;
  634.          wp->bottom_line = window->bottom_line;
  635.          wp->start_col = window->start_col;
  636.          wp->end_col   = window->end_col;
  637.          wp->vertical  = window->vertical;
  638.          if (wp->cline > wp->bottom_line)
  639.             wp->cline = wp->bottom_line;
  640.          if ((wp->cline+1L - (wp->top_line+wp->ruler)) > wp->rline)
  641.             wp->cline = (int)wp->rline;
  642.          wp->visible = TRUE;
  643.          window->visible = FALSE;
  644.          g_status.current_window = wp;
  645.          redraw_current_window( wp );
  646.          make_ruler( wp );
  647.          show_ruler( wp );
  648.       }
  649.    }
  650. }
  651.  
  652.  
  653. /*
  654.  * Name:    setup_window
  655.  * Purpose: To set the page length and the center line of a window, based
  656.  *           on the top and bottom lines.
  657.  * Date:    June 5, 1991
  658.  * Passed:  window: window to be set up
  659.  */
  660. void setup_window( WINDOW *window )
  661. {
  662.    window->page = window->bottom_line - (window->top_line + window->ruler) -
  663.                   g_status.overlap + 1;
  664.    if (window->page < 1)
  665.       window->page = 1;
  666. }
  667.  
  668.  
  669. /*
  670.  * Name:    finish
  671.  * Purpose: To remove the current window and terminate the program if no
  672.  *           more windows are left.
  673.  * Date:    June 5, 1991
  674.  * Passed:  window: information allowing access to the current window
  675.  * Notes:   Order of deciding which window becomes current window:
  676.  *          1) If any invisible window with same top and bottom line,
  677.  *          and start_col and end_col, then first invisible one becomes
  678.  *          current window.
  679.  *          2) first available invisible window becomes current window.
  680.  *          3) window above if it exists becomes current window
  681.  *          4) window below if it exists becomes current window
  682.  *          5) window right if it exists becomes current window
  683.  *          6) window left  if it exists becomes current window
  684.  *          When I added vertical windows, this routine became a LOT
  685.  *          more complicated.  To keep things reasonably sane, let's
  686.  *          only close windows that have three common edges, eg.
  687.  *
  688.  *                      ┌────┬──────────┐
  689.  *                      │    │    no    │
  690.  *                      │    ├─────┬────┤
  691.  *                      │ no │yes1 │yes1│
  692.  *                      │    ├────┬┴────┤
  693.  *                      │    │yes2│yes2 │
  694.  *                      └────┴────┴─────┘
  695.  *
  696.  *          Windows with 'no' cannot be closed.  Windows with 'yes' can
  697.  *          be combined with windows that have the same yes number.
  698.  */
  699. void finish( WINDOW *window )
  700. {
  701. register WINDOW *wp;   /* for scanning other windows */
  702. register WINDOW *win;  /* register pointer for window */
  703. file_infos *file, *fp;  /* for scanning other files */
  704. long number;            /* number of bytes removed / copied */
  705. int poof;
  706. int cline;
  707. int top, bottom;
  708. int start_col, end_col;
  709. int max_letter;
  710. int file_change = FALSE;
  711.  
  712.    win = window;
  713.    un_copy_line( win->cursor, win, TRUE );
  714.    /*
  715.     * remove old window from list
  716.     */
  717.    top = 1;
  718.    bottom = g_display.nlines;
  719.    if (win->prev == NULL && win->next == NULL)
  720.       g_status.stop = TRUE;
  721.  
  722.    /*
  723.     * remove all hidden windows that point to same file
  724.     */
  725.    file = win->file_info;
  726.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  727.       if (wp->file_info == file) {
  728.          if (!wp->visible) {
  729.             if (wp->prev == NULL) {
  730.                if (wp->next == NULL)
  731.                   g_status.stop = TRUE;
  732.                else
  733.                   g_status.window_list = wp->next;
  734.             } else
  735.                wp->prev->next = wp->next;
  736.             if (wp->next)
  737.                wp->next->prev = wp->prev;
  738.             --wp->file_info->ref_count;
  739.             free( wp );
  740.             --g_status.window_count;
  741.          }
  742.       }
  743.    }
  744.  
  745.    poof = FALSE;
  746.    if (g_status.stop != TRUE) {
  747.       /*
  748.        * see if there are any invisible windows with same top and bottom,
  749.        * lines, and start_col and end_col as this window.  start looking at
  750.        * end of window list.
  751.        */
  752.       top       = win->top_line;
  753.       bottom    = win->bottom_line;
  754.       start_col = win->start_col;
  755.       end_col   = win->end_col;
  756.       wp = g_status.window_list;
  757.       if (wp != NULL) {
  758.          while (wp->next != NULL)
  759.             wp = wp->next;
  760.       }
  761.       while (wp != NULL && poof == FALSE) {
  762.          if (wp->top_line == win->top_line && !wp->visible)
  763.             poof = TRUE;
  764.          else
  765.             wp = wp->prev;
  766.       }
  767.  
  768.       if (poof == FALSE) {
  769.          /*
  770.           * see if there are any other invisible windows.  start looking
  771.           * at the end of the window list.
  772.           */
  773.          wp = g_status.window_list;
  774.          if (wp != NULL) {
  775.             while (wp->next != NULL)
  776.                wp = wp->next;
  777.          }
  778.          while (wp != NULL && poof == FALSE) {
  779.             if (!wp->visible)
  780.                poof = TRUE;
  781.             else
  782.                wp = wp->prev;
  783.          }
  784.          if (poof == FALSE) {
  785.             /*
  786.              * see if there are any windows above
  787.              */
  788.             wp = g_status.window_list;
  789.             while (wp != NULL && poof == FALSE) {
  790.                if (wp->bottom_line+2 == win->top_line &&
  791.                    wp->start_col     == win->start_col &&
  792.                    wp->end_col       == win->end_col) {
  793.                   poof = TRUE;
  794.                   top  = wp->top_line;
  795.                } else
  796.                   wp = wp->next;
  797.             }
  798.          }
  799.          if (poof == FALSE) {
  800.             /*
  801.              * see if there are any windows below
  802.              */
  803.             wp = g_status.window_list;
  804.             while (wp != NULL && poof == FALSE) {
  805.                if (wp->top_line-2 == win->bottom_line  &&
  806.                    wp->start_col     == win->start_col &&
  807.                    wp->end_col       == win->end_col) {
  808.                   poof = TRUE;
  809.                   bottom = wp->bottom_line;
  810.                } else
  811.                   wp = wp->next;
  812.             }
  813.          }
  814.          if (poof == FALSE) {
  815.             /*
  816.              * see if there are any windows right
  817.              */
  818.             wp = g_status.window_list;
  819.             while (wp != NULL && poof == FALSE) {
  820.                if (wp->top_line    == win->top_line  &&
  821.                    wp->bottom_line == win->bottom_line &&
  822.                    wp->start_col-2 == win->end_col) {
  823.                   poof = TRUE;
  824.                   end_col = wp->end_col;
  825.                } else
  826.                   wp = wp->next;
  827.             }
  828.          }
  829.          if (poof == FALSE) {
  830.             /*
  831.              * see if there are any windows left
  832.              */
  833.             wp = g_status.window_list;
  834.             while (wp != NULL && poof == FALSE) {
  835.                if (wp->top_line    == win->top_line  &&
  836.                    wp->bottom_line == win->bottom_line &&
  837.                    wp->end_col+2   == win->start_col) {
  838.                   poof = TRUE;
  839.                   start_col = wp->start_col;
  840.                } else
  841.                   wp = wp->next;
  842.             }
  843.          }
  844.       }
  845.       if (poof) {
  846.          wp->visible = TRUE;
  847.          cline = wp->cline - (wp->top_line+wp->ruler);
  848.          wp->top_line = top;
  849.          wp->bottom_line = bottom;
  850.          wp->cline = (wp->top_line+wp->ruler) + cline;
  851.          if (wp->cline > wp->bottom_line)
  852.             wp->cline = wp->top_line+wp->ruler;
  853.          wp->start_col = start_col;
  854.          wp->end_col   = end_col;
  855.          if (start_col == 0 && end_col == g_display.ncols - 1)
  856.             wp->vertical = FALSE;
  857.          else
  858.             wp->vertical = TRUE;
  859.          check_virtual_col( wp, wp->rcol, wp->ccol );
  860.          setup_window( wp );
  861.          show_window_header( wp );
  862.          if (wp->vertical)
  863.             show_vertical_separator( wp );
  864.  
  865.          /*
  866.           * The window above, below, or previously invisible becomes the new
  867.           * current window.
  868.           */
  869.          g_status.current_window = wp;
  870.       }
  871.    }
  872.  
  873.    if (!poof && g_status.stop != TRUE)
  874.       error( WARNING, win->bottom_line, "cannot close current window" );
  875.    else {
  876.  
  877.       /*
  878.        * free unused file memory if necessary
  879.        */
  880.       if (--file->ref_count == 0) {
  881.  
  882.          /*
  883.           * if a block is marked, unmark it
  884.           */
  885.          if (file == g_status.marked_file) {
  886.             g_status.marked      = FALSE;
  887.             g_status.marked_file = NULL;
  888.          }
  889.  
  890.          for (fp=g_status.file_list; fp != NULL; fp=fp->next) {
  891.             if (fp->file_no > file->file_no)
  892.                fp->file_no--;
  893.          }
  894.          file_change = file->file_no;
  895.  
  896.          /*
  897.           * no window now refers to this file, so remove file from the list
  898.           */
  899.          if (file->prev == NULL)
  900.             g_status.file_list = file->next;
  901.          else
  902.             file->prev->next = file->next;
  903.          if (file->next)
  904.             file->next->prev = file->prev;
  905.  
  906.          /*
  907.           * close up the gap in the memory buffer
  908.           */
  909.          number = ptoul( g_status.end_mem ) - ptoul( file->end_text );
  910.          hw_move( file->start_text, file->end_text, number );
  911.          number = ptoul( file->end_text ) - ptoul( file->start_text );
  912.          g_status.end_mem = addltop( -number, g_status.end_mem );
  913.          addorsub_all_cursors( win, -number );
  914.          adjust_start_end( file, -number );
  915.  
  916.          /*
  917.           * free the memory taken by the file structure
  918.           */
  919.          free( file );
  920.          if (--g_status.file_count) {
  921.             show_file_count( g_status.file_count );
  922.             show_avail_mem( );
  923.          }
  924.       }
  925.  
  926.       /*
  927.        * remove the current window from the window list
  928.        */
  929.       if (win->prev == NULL) {
  930.          if (win->next != NULL)
  931.             g_status.window_list = win->next;
  932.       } else
  933.          win->prev->next = win->next;
  934.  
  935.       if (win->next)
  936.          win->next->prev = win->prev;
  937.  
  938.       /*
  939.        * free the memory taken by the window structure
  940.        */
  941.       free( win );
  942.       --g_status.window_count;
  943.  
  944.       if (g_status.stop == FALSE) {
  945.          g_status.current_file = wp->file_info;
  946.          wp->file_info->dirty = LOCAL;
  947.          make_ruler( wp );
  948.          show_ruler( wp );
  949.          show_window_count( g_status.window_count );
  950.          if (file_change) {
  951.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next)
  952.                if (wp->visible)
  953.                   show_window_number_letter( wp );
  954.          } else {
  955.             max_letter = 'a';
  956.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  957.                if (wp->file_info == file && wp->letter > max_letter)
  958.                   max_letter = wp->letter;
  959.             }
  960.             if (max_letter < file->next_letter - 1)
  961.                file->next_letter = max_letter + 1;
  962.          }
  963.       }
  964.    }
  965. }
  966.  
  967.  
  968. /*
  969.  * Name:    create_window
  970.  * Purpose: To allocate space for a new window structure and set up some
  971.  *           of the relevant fields.
  972.  * Date:    June 5, 1991
  973.  * Passed:  window: pointer to window pointer
  974.  *          top:    the top line of the new window
  975.  *          bottom: the bottom line of the new window
  976.  *          file:   the file structure to be associated with the new window
  977.  * Returns: OK if window could be created
  978.  *          ERROR if out of memory
  979.  */
  980. int  create_window( WINDOW **window, int top, int bottom, int start_col,
  981.                     int end_col, file_infos *file )
  982. {
  983. WINDOW *wp;            /* temporary variable - use it instead of **window */
  984. register WINDOW *prev;
  985. int rc;                 /* return code */
  986.  
  987.    rc = OK;
  988.    /*
  989.     * allocate space for new window structure
  990.     */
  991.    if ((*window = (WINDOW *)calloc( 1, sizeof(WINDOW) )) == NULL) {
  992.       error( WARNING, g_display.nlines, "out of memory for window" );
  993.       rc = ERROR;
  994.    } else {
  995.  
  996.      /*
  997.       * set up appropriate fields
  998.       */
  999.       wp              = *window;
  1000.       wp->file_info   = file;
  1001.       wp->top_line    = top+1;
  1002.       wp->bottom_line = bottom;
  1003.       wp->start_col   = start_col;
  1004.       wp->end_col     = end_col;
  1005.       wp->ruler       = mode.ruler;
  1006.       make_ruler( wp );
  1007.       wp->cline       = wp->top_line + wp->ruler;
  1008.       if (start_col == 0 && end_col == g_display.ncols-1)
  1009.          wp->vertical = FALSE;
  1010.       else
  1011.          wp->vertical = TRUE;
  1012.       wp->prev        = NULL;
  1013.       wp->next        = NULL;
  1014.  
  1015.       setup_window( wp );
  1016.  
  1017.       /*
  1018.        * add window into window list
  1019.        */
  1020.       prev = g_status.current_window;
  1021.       if (prev) {
  1022.          (*window)->prev = prev;
  1023.          if (prev->next)
  1024.             prev->next->prev = *window;
  1025.          (*window)->next = prev->next;
  1026.          prev->next = *window;
  1027.       }
  1028.       if (g_status.window_list == NULL)
  1029.          g_status.window_list = *window;
  1030.  
  1031.  
  1032.       /*
  1033.        * record that another window is referencing this file
  1034.        */
  1035.       ++file->ref_count;
  1036.       file->dirty = LOCAL;
  1037.       ++g_status.window_count;
  1038.    }
  1039.    return( rc );
  1040. }
  1041.  
  1042.  
  1043. /*
  1044.  * Name:    edit_file
  1045.  * Purpose: To allocate space for a new file structure and set up some
  1046.  *           of the relevant fields.
  1047.  * Date:    June 5, 1991
  1048.  * Passed:  name:  name of the file to edit
  1049.  * Returns: OK if file structure could be created
  1050.  *          ERROR if out of memory
  1051.  */
  1052. int  edit_file( char *name )
  1053. {
  1054. int rc;           /* return code */
  1055. int existing;
  1056. int line;
  1057. register file_infos *file; /* file structure for file belonging to new window */
  1058. file_infos *fp;
  1059. text_ptr next;      /* text pointer */
  1060. long size;
  1061.  
  1062.    rc = OK;
  1063.    line = g_display.nlines;
  1064.    if (hw_fattrib( name ) == OK) {
  1065.       existing = TRUE;
  1066.       /*
  1067.        * g_status.temp_end is set last character read in file
  1068.        */
  1069.       rc = load_file( name );
  1070.    } else {
  1071.       if (ceh.flag == ERROR)
  1072.          rc = ERROR;
  1073.       else {
  1074.          existing = FALSE;
  1075.          g_status.temp_end = cpf( g_status.end_mem );
  1076.       }
  1077.    }
  1078.  
  1079.    if (rc != ERROR) {
  1080.       /*
  1081.        * allocate a file structure for the new file
  1082.        */
  1083.       file = (file_infos *)calloc( 1, sizeof(file_infos) );
  1084.       if (file == NULL) {
  1085.          error( WARNING, g_display.nlines, "out of memory for file info" );
  1086.          rc = ERROR;
  1087.       } else {
  1088.          /*
  1089.           * add file into list
  1090.           */
  1091.          file->prev = NULL;
  1092.          file->next = NULL;
  1093.          if (g_status.file_list == NULL)
  1094.             g_status.file_list = file;
  1095.          else {
  1096.             fp = g_status.current_file;
  1097.             file->prev = fp;
  1098.             if (fp->next)
  1099.                fp->next->prev = file;
  1100.             file->next = fp->next;
  1101.             fp->next = file;
  1102.          }
  1103.       }
  1104.       if (rc != ERROR) {
  1105.          /*
  1106.           * set up all the info we need to know about a file, and
  1107.           *  record that we have used some more memory.
  1108.           */
  1109.          strcpy( file->file_name, name );
  1110.          get_fattr( name, &file->file_attrib );
  1111.          file->start_text = g_status.end_mem;
  1112.          *g_status.temp_end = CONTROL_Z;
  1113.          g_status.temp_end = cpf( g_status.temp_end );
  1114.          g_status.end_mem = g_status.temp_end + 1;
  1115.          g_status.temp_end = g_status.end_mem;
  1116.          file->end_text = g_status.end_mem;
  1117.          size = 0l;
  1118.          if (existing) {
  1119.             next = file->start_text = cpf( file->start_text );
  1120.             while ((next = find_next( next )) != NULL)
  1121.                size++;
  1122.          }
  1123.          file->length      = size;
  1124.          file->block_type  = NOTMARKED;
  1125.          file->block_end   = file->block_start = NULL;
  1126.          file->block_br    = file->block_er = 0l;
  1127.          file->block_bc    = file->block_ec = 0;
  1128.          file->ref_count   = 0;
  1129.          file->modified    = FALSE;
  1130.          file->backed_up   = FALSE;
  1131.          file->new_file    = !existing;
  1132.          file->next_letter = 'a';
  1133.          file->file_no     = ++g_status.file_count;
  1134.          g_status.current_file = file;
  1135.          make_backup_fname( file );
  1136.       }
  1137.    }
  1138.    return( rc );
  1139. }
  1140.  
  1141.  
  1142. /*
  1143.  * Name:    edit_another_file
  1144.  * Purpose: Bring in another file to editor.
  1145.  * Date:    June 5, 1991
  1146.  * Passed:  window: information allowing access to the current window
  1147.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1148.  */
  1149. void edit_another_file( WINDOW *window )
  1150. {
  1151. char fname[MAX_COLS];            /* new name for file */
  1152. register WINDOW *win;           /* put window pointer in a register */
  1153.  
  1154.    win = window;
  1155.    un_copy_line( win->cursor, win, TRUE );
  1156.    /*
  1157.     * read in name, no default
  1158.     */
  1159.    fname[0] = '\0';
  1160.    if (get_name( "File to edit: ", win->bottom_line, fname,
  1161.                  g_display.message_color ) == OK)
  1162.       attempt_edit_display( fname, LOCAL );
  1163. }
  1164.  
  1165.  
  1166. /*
  1167.  * Name:    edit_next_file
  1168.  * Purpose: edit next file on command line.
  1169.  * Date:    January 6, 1992
  1170.  * Passed:  window: information allowing access to the current window
  1171.  * Notes:   New window replaces old window.  Old window becomes invisible.
  1172.  */
  1173. int  edit_next_file( WINDOW *window )
  1174. {
  1175. char name[MAX_COLS];            /* new name for file */
  1176. int i;
  1177. int update_type;
  1178. register int rc = ERROR;
  1179. register WINDOW *win;           /* put window pointer in a register */
  1180.  
  1181.    win = window;
  1182.    update_type = win == NULL ? GLOBAL : LOCAL;
  1183.    if (g_status.arg < g_status.argc) {
  1184.       if (win != NULL)
  1185.          un_copy_line( win->cursor, win, TRUE );
  1186.  
  1187.       /*
  1188.        * while we haven't found a valid file, search thru the command
  1189.        * line path.
  1190.        * we may have an invalid file name when we finish matching all
  1191.        * files according to a pattern.  then, we need to go to the next
  1192.        * command line argument if it exists.
  1193.        */
  1194.       while (rc == ERROR && g_status.arg < g_status.argc) {
  1195.  
  1196.          /*
  1197.           * if we haven't starting searching for a file, check to see if
  1198.           * the file is a valid file name.  if no file is found, then let's
  1199.           * see if we can find according to a search pattern.
  1200.           */
  1201.          if (g_status.found_first == FALSE) {
  1202.             strcpy( name, g_status.argv[g_status.arg] );
  1203.             rc = get_fattr( name, &i );
  1204.  
  1205.             /*
  1206.              * a new or blank file generates a return code of 2.
  1207.              * a pattern with wild cards generates a return code of 3.
  1208.              */
  1209.             if (rc == OK || rc == 2) {
  1210.                ++g_status.arg;
  1211.                rc = OK;
  1212.  
  1213.             /*
  1214.              * if we get this far, we got an invalid path name.
  1215.              *  let's try to find a matching file name using pattern.
  1216.              */
  1217.             } else if (rc != ERROR) {
  1218.                rc = findfirst( &g_status.dta, name, NORMAL | READ_ONLY |
  1219.                                HIDDEN | SYSTEM | ARCHIVE );
  1220.  
  1221.                /*
  1222.                 * if we found a file using wildcard characters,
  1223.                 * set the g_status.found_first flag to true so we can
  1224.                 * find the next matching file.  we need to save the
  1225.                 * pathname stem so we know which directory we are working in.
  1226.                 */
  1227.                if (rc == OK) {
  1228.                   g_status.found_first = TRUE;
  1229.                   i = strlen( name ) - 1;
  1230.                   while (i >= 0) {
  1231.                      if (name[i] == ':' || name[i] == '\\')
  1232.                         break;
  1233.                      --i;
  1234.                   }
  1235.                   name[++i] = '\0';
  1236.                   strcpy( g_status.path, name );
  1237.                   strcpy( name, g_status.path );
  1238.                   strcat( name, g_status.dta.name );
  1239.                } else {
  1240.                   ++g_status.arg;
  1241.                   if (win != NULL)
  1242.                      error( WARNING, win->bottom_line,
  1243.                             "Invalid path or file name " );
  1244.                }
  1245.             } else if (rc == ERROR)
  1246.                ++g_status.arg;
  1247.          } else {
  1248.  
  1249.             /*
  1250.              * we already found one file with wild card characters,
  1251.              * find the next matching file.
  1252.              */
  1253.             rc = findnext( &g_status.dta );
  1254.             if (rc == OK) {
  1255.                strcpy( name, g_status.path );
  1256.                strcat( name, g_status.dta.name );
  1257.             } else {
  1258.                g_status.found_first = FALSE;
  1259.                ++g_status.arg;
  1260.             }
  1261.          }
  1262.  
  1263.          /*
  1264.           * if everything is everything so far, set up the file
  1265.           * and window structures and bring the file into the editor.
  1266.           */
  1267.          if (rc == OK)
  1268.             rc = attempt_edit_display( name, update_type );
  1269.  
  1270.          /*
  1271.           * either there are no more matching files or we had an
  1272.           * invalid file name, set rc to ERROR and let's look at the
  1273.           * next file name or pattern on the command line.
  1274.           */
  1275.          else
  1276.             rc = ERROR;
  1277.       }
  1278.    }
  1279.    if (rc == ERROR  &&  g_status.arg >= g_status.argc  &&  win != NULL)
  1280.       error( WARNING, win->bottom_line, "No more files to load " );
  1281.    return( rc );
  1282. }
  1283.  
  1284.  
  1285. /*
  1286.  * Name:    attempt_edit_display
  1287.  * Purpose: try to load then display a file
  1288.  * Date:    June 5, 1991
  1289.  * Passed:  fname:       file name to load
  1290.  *          update_type: update current window or entire screen
  1291.  * Notes:   When we first start the editor, we need to update the entire
  1292.  *          screen.  When we load in a new file, we only need to update
  1293.  *          the current window.
  1294.  */
  1295. int  attempt_edit_display( char *fname, int update_type )
  1296. {
  1297. register int rc;
  1298. WINDOW *win;
  1299.  
  1300.    rc = edit_file( fname );
  1301.    if (rc != ERROR) {
  1302.       rc = initialize_window( );
  1303.       if (rc != ERROR) {
  1304.          win = g_status.current_window;
  1305.          if (update_type == LOCAL) {
  1306.             redraw_current_window( win );
  1307.             show_file_count( g_status.file_count );
  1308.             show_window_count( g_status.window_count );
  1309.             show_avail_mem( );
  1310.          } else if (update_type == GLOBAL)
  1311.             redraw_screen( win );
  1312.          if (win->file_info->new_file) {
  1313.             g_status.command = AddLine;
  1314.             insert_newline( win );
  1315.             win->file_info->modified = FALSE;
  1316.          }
  1317.       }
  1318.    }
  1319.    return( rc );
  1320. }
  1321.  
  1322.  
  1323. /*
  1324.  * Name:    make_backup_fname
  1325.  * Purpose: add .bak to file name
  1326.  * Date:    January 6, 1992
  1327.  * Passed:  file: information allowing access to the current file
  1328.  */
  1329. void make_backup_fname( file_infos *file )
  1330. {
  1331. char name[MAX_COLS];            /* new name for file */
  1332. char *p;
  1333. int i;
  1334. int len;
  1335.  
  1336.    /*
  1337.     * if this is a new file then don't create a backup - can't backup
  1338.     *   a nonexisting file.
  1339.     */
  1340.    if (file->new_file)
  1341.       file->backed_up = TRUE;
  1342.  
  1343.    /*
  1344.     * find the file name extension if it exists
  1345.     */
  1346.    else {
  1347.       strcpy( name, file->file_name );
  1348.       len = strlen( name );
  1349.       for (i=len,p=name+len; i>=0; i--) {
  1350.  
  1351.          /*
  1352.           * we found the '.' extension character.  get out
  1353.           */
  1354.          if (*p == '.')
  1355.             break;
  1356.  
  1357.          /*
  1358.           * we found the drive or directory character.  no extension so
  1359.           *  set the pointer to the end of file name string.
  1360.           */
  1361.          else if (*p == '\\' || *p == ':') {
  1362.             p = name + len;
  1363.             break;
  1364.  
  1365.          /*
  1366.           * we're at the beginning of the string - no '.', drive, or directory
  1367.           *  char was found.  set the pointer to the end of file name string.
  1368.           */
  1369.          } else if (i == 0) {
  1370.             p = name + len;
  1371.             break;
  1372.          }
  1373.          --p;
  1374.       }
  1375.       strcpy( p, ".bak" );
  1376.       strcpy( file->backup_fname, name );
  1377.    }
  1378. }
  1379.