home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / editors / tde150.arj / UTILS.C < prev    next >
C/C++ Source or Header  |  1992-04-01  |  67KB  |  2,252 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 - miscellaneous utilities
  10.  * Purpose: This file contains miscellaneous functions that were required
  11.  *           in more than one of the other files, or were thought to be
  12.  *           likely to be used elsewhere in the future.
  13.  * File:    utils.c
  14.  * Author:  Douglas Thomson
  15.  * System:  this file is intended to be system-independent
  16.  * Date:    October 1, 1989
  17.  */
  18. /*********************  end of original comments   ********************/
  19.  
  20.  
  21. /*
  22.  * The utility routines have been EXTENSIVELY rewritten.  Update screens as
  23.  * needed.  Most times, only one line has changed.  Just show changed line
  24.  * in all windows if it is on screen.
  25.  *
  26.  * Support routines for text lines longer than screen width have been added.
  27.  * Currently support lines as long as 255 bytes.  If longer lines are needed,
  28.  * the assembly routines need to be modified since they use bytes (a byte
  29.  * goes from 255 to 0, unsigned).
  30.  *
  31.  * New editor name:  tde, the Thomson-Davis Editor.
  32.  * Author:           Frank Davis
  33.  * Date:             June 5, 1991, version 1.0
  34.  * Date:             July 29, 1991, version 1.1
  35.  * Date:             October 5, 1991, version 1.2
  36.  * Date:             January 20, 1992, version 1.3
  37.  * Date:             February 17, 1992, version 1.4
  38.  * Date:             April 1, 1992, version 1.5
  39.  *
  40.  * This modification of Douglas Thomson's code is released into the
  41.  * public domain, Frank Davis.  You may distribute it freely.
  42.  */
  43.  
  44. #include "tdestr.h"
  45. #include "common.h"
  46. #include "define.h"
  47. #include "tdefunc.h"
  48. #ifdef __TURBOC__
  49.   #include <dir.h>        /* for making temporary file names etc */
  50. #endif
  51. #if defined( __MSC__ )
  52.    #include <dos.h>
  53.    #include <io.h>
  54. #endif
  55.  
  56.  
  57. /*
  58.  * Name:    myisalnum
  59.  * Purpose: To determine whether or not a character is part of a "word",
  60.  *           which in languages like Pascal means a letter, digit or
  61.  *           underscore.
  62.  * Date:    October 1, 1989
  63.  * Passed:  c: the character to be tested
  64.  * Returns: TRUE if c is an alphanumeric or '_' character, FALSE otherwise
  65.  */
  66. int  myisalnum( int c )
  67. {
  68.    return( isalnum( c ) || (c == '_') );
  69. }
  70.  
  71.  
  72. /*
  73.  * Name:    check_virtual_col
  74.  * Purpose: ensure integrity of rcol, ccol, and bcol
  75.  * Date:    June 5, 1991
  76.  * Passed:  window: current window
  77.  *          rcol: real column of cursor
  78.  *          ccol: current or logical column of cursor
  79.  */
  80. void check_virtual_col( WINDOW *window, int rcol, int ccol )
  81. {
  82. register int bcol;
  83. int start_col;
  84. int end_col;
  85. file_infos *file;
  86.  
  87.    file      = window->file_info;
  88.    bcol      = window->bcol;
  89.    start_col = window->start_col;
  90.    end_col   = window->end_col;
  91.  
  92.    /*
  93.     * is logical column past end of screen?
  94.     */
  95.    if (ccol > end_col) {
  96. /*      ccol = start_col + (end_col + 1 - start_col) / 2;  */
  97.       ccol = end_col;
  98.       bcol = rcol - (ccol - start_col);
  99.       file->dirty = LOCAL;
  100.    }
  101.  
  102.    /*
  103.     * is logical column behind start of screen?
  104.     */
  105.    if (ccol < start_col) {
  106.       if (bcol >= (start_col - ccol))
  107.          bcol -= (start_col - ccol);
  108.       ccol = start_col;
  109.       file->dirty = LOCAL;
  110.    }
  111.  
  112.    /*
  113.     * is real column < base column?
  114.     */
  115.    if (rcol < bcol) {
  116.       ccol = rcol + start_col;
  117.       bcol = 0;
  118.       if (ccol > end_col) {
  119.          bcol = rcol;
  120.          ccol = start_col;
  121.       }
  122.       file->dirty = LOCAL;
  123.    }
  124.  
  125.    /*
  126.     * current column + base column MUST equal real column
  127.     */
  128.    if ((ccol - start_col) + bcol != rcol) {
  129.       if (bcol < 0 || bcol > rcol) {
  130.          bcol = rcol;
  131.          file->dirty = LOCAL;
  132.       }
  133.       ccol = rcol - bcol + start_col;
  134.       if (ccol > end_col) {
  135.          bcol = rcol;
  136.          ccol = start_col;
  137.          file->dirty = LOCAL;
  138.       }
  139.    }
  140.  
  141.    /*
  142.     * rcol CANNOT be negative
  143.     */
  144.    if (rcol < 0) {
  145.       rcol = bcol = 0;
  146.       ccol = start_col;
  147.       file->dirty = LOCAL;
  148.    }
  149.  
  150.    if (rcol >= MAX_LINE_LENGTH) {
  151.       rcol = MAX_LINE_LENGTH - 1;
  152.       bcol = rcol - (ccol - start_col);
  153.    }
  154.  
  155.    window->bcol = bcol;
  156.    window->ccol = ccol;
  157.    window->rcol = rcol;
  158. }
  159.  
  160.  
  161. /*
  162.  * Name:    copy_line
  163.  * Purpose: To copy the cursor line, if necessary, into the current line
  164.  *           buffer, so that changes can be made efficiently.
  165.  * Date:    June 5, 1991
  166.  * Passed:  text_line: line to be copied to line buffer
  167.  *          line: line to display error message
  168.  * Notes:   See un_copy_line, the reverse operation.  Terminate text strings
  169.  *          with CONTROL_Z.  DO NOT use the C library string functions on
  170.  *          text in g_status.line_buff.
  171.  */
  172. void copy_line( text_ptr text_line, int line )
  173. {
  174. char *d;      /* destination of copy */
  175. text_ptr s;   /* source of copy */
  176. register int len;
  177.  
  178.    if (g_status.copied == FALSE) {
  179.       g_status.copied = TRUE;
  180.       /*
  181.        * copy the cursor line to the line buffer
  182.        */
  183.       d = g_status.line_buff;
  184.       g_status.buff_line = text_line;
  185.       s = cpf( text_line );
  186.       len = linelen( s );
  187.       if (s[len] == '\n')
  188.          ++len;
  189.       if (len >= g_display.line_length) {
  190.          len = g_display.line_length;
  191.          error( WARNING, line,  "line buffer overflow - rest of line ignored" );
  192.       }
  193.       _fmemcpy( d, s, len );
  194.       d[len] = CONTROL_Z;
  195.    }
  196. }
  197.  
  198.  
  199. /*
  200.  * Name:    un_copy_line
  201.  * Purpose: To copy the cursor line, if necessary, from the current line
  202.  *           buffer, shifting the main text to make the right amount of
  203.  *           room.
  204.  * Date:    June 5, 1991
  205.  * Passed:  test_line:  pointer to location in file to copy line buffer
  206.  *          window:  pointer to current window info
  207.  *          del_trailing:  delete the trailing blanks at eol? TRUE or FALSE
  208.  * Notes:   For some functions, trailing spaces should not be removed when
  209.  *           returning the line buffer to the main text.  The JoinLine function
  210.  *           is a good example.  We need to leave trailing space so when we
  211.  *           join lines - the current line will extend at least up to
  212.  *           the column of the cursor.  We need to leave trailing space
  213.  *           during BOX block operations.
  214.  *          See copy_line, the reverse operation.
  215.  */
  216. void un_copy_line( text_ptr text_line, WINDOW *window, int del_trailing )
  217. {
  218. char *source;    /* source for block move and for copying buffer line */
  219. text_ptr dest;   /* destination for block move and copy */
  220. text_ptr p;
  221. long number;     /* length of block move */
  222. int space;
  223. int len;         /* length of current line buffer text */
  224. int curs_len;    /* length of cursor line */
  225. int prompt_line;
  226. int i;
  227. int rc;
  228. file_infos *file;
  229.  
  230.    if (g_status.copied == TRUE) {
  231.  
  232.       file = window->file_info;
  233.       /*
  234.        * file has changed.  lets create the back_up if needed
  235.        */
  236.       if (mode.do_backups == TRUE) {
  237.          if (file->backed_up == FALSE) {
  238.             rc = save_backup( window );
  239.             if (rc == ERROR)
  240.                error( WARNING, window->bottom_line,
  241.                       "Error writing file or disk full" );
  242.             else
  243.                file->backed_up = TRUE;
  244.          }
  245.       }
  246.  
  247.       /*
  248.        * if we are deleting the entire line, don't worry about the
  249.        * deleting the trailing space, since we're deleting entire line.
  250.        */
  251.       if (g_status.command == DeleteLine)
  252.          del_trailing = FALSE;
  253.  
  254.       /*
  255.        * work out the lengths of the old cursor line (including the \n if any)
  256.        *  and the new current line buffer text.
  257.        */
  258.       prompt_line = window->bottom_line;
  259.       text_line = cpf( text_line );
  260.       curs_len = linelen( text_line );
  261.       if (text_line[curs_len] == '\n')
  262.          ++curs_len;
  263.  
  264.  
  265.       if (curs_len > MAX_LINE_LENGTH) {
  266.          curs_len = MAX_LINE_LENGTH;
  267.          del_trailing = FALSE;
  268.       }
  269.       if (del_trailing && mode.trailing) {
  270.          len = linelen( g_status.line_buff );
  271.          i = find_CONTROL_Z( g_status.line_buff ) + 1;
  272.          i -= len;
  273.          for (source=g_status.line_buff+len-1; len > 0; len--, source--) {
  274.             if (*source == ' ')
  275.                memmove( source, source+1, i );
  276.             else
  277.                break;
  278.          }
  279.          if (g_status.command != WordWrap) {
  280.             file->dirty = GLOBAL;
  281.             show_changed_line( window );
  282.          }
  283.       }
  284.       len = find_CONTROL_Z( g_status.line_buff );
  285.       space = len - curs_len;
  286.  
  287.       /*
  288.        * if the main text buffer has run out of space, then only part of the
  289.        *  current line can be moved back into the main buffer. Warn the user
  290.        *  that some of the current line has been lost
  291.        */
  292.       if (ptoul( g_status.end_mem ) + (long)space >= ptoul( g_status.max_mem )) {
  293.          error( WARNING, prompt_line, "buffer full, part line truncated" );
  294.          len = curs_len + (int) (ptoul( g_status.max_mem ) -
  295.                                  ptoul( g_status.end_mem ));
  296.       }
  297.  
  298.       /*
  299.        * move text to either make room for the extra characters in the new
  300.        *  line, or else close up the gap.
  301.        */
  302.       p = text_line + curs_len;
  303.       dest = addltop( (long)space, p );
  304.       number = ptoul( g_status.end_mem ) - ptoul( p );
  305.       hw_move( dest, p, number );
  306.       g_status.end_mem = addltop( (long)space, g_status.end_mem );
  307.  
  308.       /*
  309.        * now copy the line buffer into the space just created
  310.        */
  311.       _fmemcpy( text_line, g_status.line_buff, len );
  312.       g_status.copied = FALSE;
  313.       file->modified = TRUE;
  314.       adjust_start_end( file, space );
  315.       addorsub_all_cursors( window, space );
  316.       show_avail_mem( );
  317.    }
  318. }
  319.  
  320.  
  321. /*
  322.  * Name:    load_undo_buffer
  323.  * Purpose: To copy the cursor line to the undo buffer.
  324.  * Date:    September 26, 1991
  325.  * Passed:  line_to_undo:  pointer to line in file to save
  326.  * Notes:   save the last UNDO_MAX changed lines in a stack.  when we
  327.  *          overflow the stack, dump the oldest line.  don't worry
  328.  *          about which file the line comes from - just load the stack.
  329.  */
  330. void load_undo_buffer( text_ptr line_to_undo )
  331. {
  332. register char *s;       /*  char pointer to stack */
  333. char *d;
  334. int top;                /* top of stack */
  335. register int len;
  336.  
  337.    /*
  338.     * if the stack is empty, g_status.undo_head will be -1.  set it to
  339.     *  0, the first buffer in the stack.
  340.     */
  341.    if (g_status.undo_head < 0)
  342.       g_status.undo_head = 0;
  343.  
  344.    /*
  345.     * if the stack overflows, dump the oldest line.
  346.     */
  347.    else if (g_status.undo_head == UNDO_MAX) {
  348.       d = (char *)g_status.undo_buffer;
  349.       s = d + BUFF_SIZE;
  350.       memmove( d, s, (UNDO_MAX * BUFF_SIZE) - BUFF_SIZE );
  351.    }
  352.    len = linelen( line_to_undo );
  353.    if (line_to_undo[len] == '\n')
  354.       ++len;
  355.    top = g_status.undo_head;
  356.    if (top == UNDO_MAX)
  357.       --top;
  358.    s = &g_status.undo_buffer[top][0];
  359.    hw_move( s, line_to_undo, len );
  360.    if (s[len-1] != '\n')
  361.       s[len++] = '\n';
  362.    s[len] = CONTROL_Z;
  363.    if (g_status.undo_head < UNDO_MAX)
  364.       ++g_status.undo_head;
  365. }
  366.  
  367.  
  368. /*
  369.  * Name:    load_file
  370.  * Purpose: To read in a given file at the end of the main text buffer.
  371.  * Date:    June 5, 1991
  372.  * Passed:  name:   path name of file to be read
  373.  * Returns: OK if file read successfully
  374.  *          ERROR if any problem (such as out of buffer space)
  375.  */
  376. int  load_file( char *name )
  377. {
  378.    /*
  379.     * make sure this gets set properly even if there is no file!
  380.     */
  381.    g_status.temp_end = g_status.end_mem;
  382.  
  383.    return( hw_load( name, g_status.end_mem, g_status.max_mem,
  384.            &g_status.temp_end, g_display.nlines ) );
  385. }
  386.  
  387.  
  388. /*
  389.  * Name:    set_prompt
  390.  * Purpose: To display a prompt, highlighted, at the bottom of the screen.
  391.  * Date:    October 1, 1989
  392.  * Passed:  prompt: prompt to be displayed
  393.  *          line:   line to display prompt
  394.  */
  395. void set_prompt( char *prompt, int line )
  396. {
  397. register int prompt_col;
  398.  
  399.    /*
  400.     * work out where the answer should go
  401.     */
  402.    prompt_col = strlen( prompt );
  403.  
  404.    /*
  405.     * output the prompt
  406.     */
  407.    s_output( prompt, line, 0, g_display.message_color );
  408.    eol_clear( prompt_col, line, g_display.message_color );
  409.  
  410.    /*
  411.     * put cursor at end of prompt
  412.     */
  413.    xygoto( prompt_col, line );
  414. }
  415.  
  416.  
  417. /*
  418.  * Name:    get_name
  419.  * Purpose: To prompt the user and read the string entered in response.
  420.  * Date:    October 1, 1989
  421.  * Passed:  prompt: prompt to offer the user
  422.  *          line:   line to display prompt
  423.  *          name:   default answer
  424.  *          color:  color to display prompt
  425.  * Returns: name:   user's answer
  426.  *          OK if user entered something
  427.  *          ERROR if user aborted the command
  428.  * Notes:   Editing of the line is supported.
  429.  */
  430. int get_name( char *prompt, int line, char *name, int color )
  431. {
  432. int col;                /* cursor column for answer */
  433. int c;                  /* character user just typed */
  434. char *cp;               /* cursor position in answer */
  435. char *answer;           /* user's answer */
  436. int first = TRUE;       /* first character typed */
  437. register int len;       /* length of answer */
  438. int plen;               /* length of prompt */
  439. int func;               /* function of key pressed */
  440. int stop;               /* flag to stop getting characters */
  441. char *p;                /* for copying text in answer */
  442. char buffer[MAX_COLS+2];/* line on which name is being entered */
  443. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  444. int normal;
  445.  
  446.    /*
  447.     * set up prompt and default
  448.     */
  449.    strcpy( buffer, prompt );
  450.    plen = strlen( prompt );
  451.    answer = buffer + plen;
  452.    strcpy( answer, name );
  453.  
  454.    /*
  455.     * let user edit default string
  456.     */
  457.    len = strlen( answer );
  458.    col = strlen( buffer );
  459.    g_status.prompt_line = line;
  460.    g_status.prompt_col = col;
  461.    cp = answer + len;
  462.    normal = g_display.text_color;
  463.    save_screen_line( 0, line, line_buff );
  464.    s_output( buffer, line, 0, color );
  465.    eol_clear( col, line, normal );
  466.    for (stop = FALSE; stop == FALSE;) {
  467.       xygoto( col, line );
  468.       c = getkey( );
  469.       func = getfunc( c );
  470.  
  471.       /*
  472.        * User may have redefined the Enter and ESC keys.  Make the Enter key
  473.        * perform a Rturn in this function. Make the ESC key do an AbortCommand.
  474.        */
  475.       if (c == RTURN)
  476.          func = Rturn;
  477.       else if (c == ESC)
  478.          func = AbortCommand;
  479.       switch (func) {
  480.          case ToggleSearchCase :
  481.             bm.search_case = bm.search_case == IGNORE ? MATCH : IGNORE;
  482.             show_search_case( );
  483.             break;
  484.          case Rturn       :
  485.          case NextLine    :
  486.          case BegNextLine :
  487.             answer[len] = '\0';
  488.             strcpy( name, answer );
  489.             /*
  490.              * finished
  491.              */
  492.             stop = TRUE;
  493.             break;
  494.          case BackSpace :
  495.             /*
  496.              * delete to left of cursor
  497.              */
  498.             if (cp > answer) {
  499.                for (p=cp-1; p < answer+len; p++) {
  500.                   *p = *(p+1);
  501.                }
  502.                --len;
  503.                --col;
  504.                --cp;
  505.                c_output( ' ', plen+len, line, normal );
  506.                s_output( cp, line, col, color );
  507.                *(answer + len) = '\0';
  508.             }
  509.             break;
  510.          case DeleteChar :
  511.             /*
  512.              * delete char under cursor
  513.              */
  514.             if (*cp) {
  515.                for (p=cp; p < answer+len; p++) {
  516.                   *p = *(p+1);
  517.                }
  518.                --len;
  519.                c_output( ' ', plen+len, line, normal );
  520.                s_output( cp, line, col, color );
  521.                *(answer + len) = '\0';
  522.             }
  523.             break;
  524.          case DeleteLine :
  525.             /*
  526.              * delete current line
  527.              */
  528.             col = plen;
  529.             cp = answer;
  530.             *cp = '\0';
  531.             len = 0;
  532.             eol_clear( col, line, normal );
  533.             break;
  534.          case AbortCommand :
  535.             stop = TRUE;
  536.             break;
  537.          case CharLeft :
  538.             /*
  539.              * move cursor left
  540.              */
  541.             if (cp > answer) {
  542.                col--;
  543.                cp--;
  544.             }
  545.             break;
  546.          case CharRight :
  547.             /*
  548.              * move cursor right
  549.              */
  550.             if (*cp) {
  551.                col++;
  552.                cp++;
  553.              }
  554.              break;
  555.          case BegOfLine :
  556.             /*
  557.              * move cursor to start of line
  558.              */
  559.             col = plen;
  560.             cp = answer;
  561.             break;
  562.          case EndOfLine :
  563.             /*
  564.              * move cursor to end of line
  565.              */
  566.             col = plen + len;
  567.             cp = answer + len;
  568.             break;
  569.          default :
  570.             if (c < 0x100) {
  571.                /*
  572.                 * insert character at cursor
  573.                 */
  574.                if (first) {
  575.                   /*
  576.                    * delete previous answer
  577.                    */
  578.                   col = plen;
  579.                   cp = answer;
  580.                   *cp = '\0';
  581.                   len = 0;
  582.                   eol_clear( col, line, normal );
  583.                }
  584.  
  585.                /*
  586.                 * insert new character
  587.                 */
  588.                if (col < g_display.ncols-1) {
  589.                   if (*cp == '\0') {
  590.                      ++len;
  591.                      *(answer + len) = '\0';
  592.                   }
  593.                   *cp = (char)c;
  594.                   c_output( c, col, line, color );
  595.                   ++cp;
  596.                   ++col;
  597.                }
  598.             }
  599.             break;
  600.       }
  601.       first = FALSE;
  602.    }
  603.    restore_screen_line( 0, line, line_buff );
  604.    return( func == AbortCommand ? ERROR : OK );
  605. }
  606.  
  607.  
  608. /*
  609.  * Name:    get_yn
  610.  * Purpose: To input a response of yes or no.
  611.  * Date:    October 1, 1989
  612.  * Returns: the user's answer.  A_??? - see tdestr.h
  613.  */
  614. int  get_yn( void )
  615. {
  616. int c;   /* the user's response */
  617. register int rc;  /* return code */
  618.  
  619.    for (rc=-1; rc<0;) {
  620.       c = getkey( );
  621.       if (getfunc( c ) == AbortCommand || c == ESC)
  622.          rc = A_ABORT;
  623.       else {
  624.          switch ( c ) {
  625.             case 'Y':
  626.             case 'y':
  627.                rc = A_YES;
  628.                break;
  629.             case 'N':
  630.             case 'n':
  631.                rc = A_NO;
  632.                break;
  633.          }
  634.       }
  635.    }
  636.    return( rc );
  637. }
  638.  
  639.  
  640. /*
  641.  * Name:    get_lr
  642.  * Purpose: To input a response of yes or no.
  643.  * Date:    October 1, 1989
  644.  * Returns: the user's answer.  A_??? - see tdestr.h
  645.  */
  646. int  get_lr( void )
  647. {
  648. int c;   /* the user's response */
  649. register int rc;  /* return code */
  650.  
  651.    for (rc=OK; rc==OK;) {
  652.       c = getkey( );
  653.       if (getfunc( c ) == AbortCommand || c == ESC)
  654.          rc = ERROR;
  655.       else {
  656.          switch ( c ) {
  657.             case 'L':
  658.             case 'l':
  659.                rc = LEFT;
  660.                break;
  661.             case 'R':
  662.             case 'r':
  663.                rc = RIGHT;
  664.                break;
  665.          }
  666.       }
  667.    }
  668.    return( rc );
  669. }
  670.  
  671.  
  672. /*
  673.  * Name:    get_oa
  674.  * Purpose: To input a response of overwrite or append.
  675.  * Date:    October 1, 1989
  676.  * Returns: the user's answer.  A_??? - see tdestr.h
  677.  */
  678. int get_oa( void )
  679. {
  680. int c;            /* the user's response */
  681. register int rc;  /* return code */
  682. int func;
  683.  
  684.    rc = 0;
  685.    while (rc != AbortCommand && rc != A_OVERWRITE && rc != A_APPEND) {
  686.       c = getkey( );
  687.       func = getfunc( c );
  688.       if (func == AbortCommand || c == ESC)
  689.          rc = AbortCommand;
  690.       switch ( c ) {
  691.          case 'O':
  692.          case 'o':
  693.             rc = A_OVERWRITE;
  694.             break;
  695.          case 'A':
  696.          case 'a':
  697.             rc = A_APPEND;
  698.             break;
  699.       }
  700.    }
  701.    return( rc );
  702. }
  703.  
  704.  
  705. /*
  706.  * Name:    show_eof
  707.  * Purpose: display eof message
  708.  * Date:    September 16, 1991
  709.  * Passed:  line: line to display "<=== eof ===>"
  710.  */
  711. void show_eof( WINDOW *window )
  712. {
  713. register int color;
  714. char temp[MAX_COLS+2];
  715.  
  716.    strcpy( temp, mode.eof );
  717.    color = window->end_col + 1 - window->start_col;
  718.    if (strlen( temp ) > (unsigned)color)
  719.       temp[color] = '\0';
  720.    color = g_display.eof_color;
  721.    window_eol_clear( window, color );
  722.    s_output( temp, window->cline, window->start_col, color );
  723. }
  724.  
  725.  
  726. /*
  727.  * Name:    display_current_window
  728.  * Purpose: display text in current window
  729.  * Date:    June 5, 1991
  730.  * Passed:  window: current window
  731.  * Notes:   use a temporary window structure, "w", to do the dirty work.
  732.  */
  733. void display_current_window( WINDOW *window )
  734. {
  735. text_ptr p;         /* successive lines above the cursor */
  736. int count;          /* number of lines updated so far */
  737. int number;         /* number of lines visible in window */
  738. register int i;     /* register variable */
  739. WINDOW w;          /* scratch window structure */
  740. long length;        /* length of file.  number of lines in the file */
  741. int  curl;          /* current line on screen, window->cline */
  742.  
  743.    /*
  744.     * initialize the scratch variables
  745.     */
  746.    number = window->bottom_line - ((window->top_line + window->ruler) - 1);
  747.    dup_window_info( &w, window );
  748.    w.cursor = cpb( w.cursor );
  749.    curl   = window->cline;
  750.    count  = window->cline - (window->top_line + window->ruler);
  751.    length = window->file_info->length;
  752.  
  753.    /*
  754.     * find the first text line on the screen
  755.     */
  756.    for (i=count; i>0; i--) {
  757.       p = find_prev( w.cursor );
  758.       if (p) {
  759.          w.cursor = p;
  760.          --w.cline;
  761.          --w.rline;
  762.       }
  763.    }
  764.  
  765.    /*
  766.     * start at the top of the window and display a window full of text
  767.     */
  768.    w.cursor = cpf( w.cursor );
  769.    for (i=number; i>0; i--) {
  770.       if (w.cursor) {
  771.          if (w.rline <= length) {
  772.  
  773.             /*
  774.              * if this is window->cline, do not show the line because we
  775.              * show the curl at the end of this function.  don't show it twice
  776.              */
  777.             if (w.cline != curl)
  778.                update_line( &w );
  779.          } else
  780.             show_eof( &w );
  781.          w.cursor = find_next( w.cursor );
  782.       } else
  783.          window_eol_clear( &w, COLOR_TEXT );
  784.       ++w.cline;
  785.       ++w.rline;
  786.    }
  787.    show_asterisk( window );
  788.    show_curl_line( window );
  789. }
  790.  
  791.  
  792. /*
  793.  * Name:    redraw_screen
  794.  * Purpose: display all visible windows
  795.  * Date:    June 5, 1991
  796.  * Passed:  window: current window
  797.  */
  798. void redraw_screen( WINDOW *window )
  799. {
  800. register WINDOW *above;        /* window above current */
  801. register WINDOW *below;        /* window below current */
  802.  
  803.    cls( );
  804.    /*
  805.     * display the current window
  806.     */
  807.    redraw_current_window( window );
  808.  
  809.    /*
  810.     * now update all the other windows
  811.     */
  812.    above = below = window;
  813.    while (above->prev || below->next) {
  814.       if (above->prev) {
  815.          above = above->prev;
  816.          redraw_current_window( above );
  817.       }
  818.       if (below->next) {
  819.          below = below->next;
  820.          redraw_current_window( below );
  821.       }
  822.    }
  823.    window->file_info->dirty = FALSE;
  824.    show_modes( );
  825. }
  826.  
  827.  
  828. /*
  829.  * Name:    redraw_current_window
  830.  * Purpose: redraw all info in window
  831.  * Date:    July 13, 1991
  832.  * Passed:  window: current window
  833.  */
  834. void redraw_current_window( WINDOW *window )
  835. {
  836.  
  837.    /*
  838.     * display the current window
  839.     */
  840.    if (window->visible) {
  841.       display_current_window( window );
  842.       show_window_header( window );
  843.       show_ruler( window );
  844.       show_ruler_pointer( window );
  845.       if (window->vertical)
  846.          show_vertical_separator( window );
  847.    }
  848. }
  849.  
  850.  
  851. /*
  852.  * Name:    show_changed_line
  853.  * Purpose: Only one line was changed in file, just show it
  854.  * Date:    June 5, 1991
  855.  * Passed:  window: current window
  856.  */
  857. void show_changed_line( WINDOW *window )
  858. {
  859. WINDOW *above;                 /* window above current */
  860. WINDOW *below;                 /* window below current */
  861. WINDOW w;                      /* scratch window structure */
  862. long changed_line;              /* line number in file that was changed */
  863. long top_line, bottom_line;     /* top and bottom line in file on screen */
  864. int line_on_screen;             /* is changed line on screen? */
  865. file_infos *file;               /* file pointer */
  866.  
  867.    file = window->file_info;
  868.    if ((file->dirty == LOCAL || file->dirty == GLOBAL) && window->visible)
  869.       show_curl_line( window );
  870.    changed_line = window->rline;
  871.  
  872.    /*
  873.     * now update the line in all other windows
  874.     */
  875.    if (file->dirty != LOCAL) {
  876.       above = below = window;
  877.       while (above->prev || below->next) {
  878.          if (above->prev) {
  879.             above = above->prev;
  880.             dup_window_info( &w, above );
  881.          } else if (below->next) {
  882.             below = below->next;
  883.             dup_window_info( &w, below );
  884.          }
  885.  
  886.          /*
  887.           * is this window the changed file and is it visible?
  888.           */
  889.          if (w.file_info == window->file_info && w.visible) {
  890.  
  891.             /*
  892.              * calculate file lines at top and bottom of screen.
  893.              * the changed line may not be the curl in other windows.
  894.              */
  895.             line_on_screen = FALSE;
  896.             top_line = w.rline - (w.cline - (w.top_line + w.ruler));
  897.             bottom_line = w.rline + (w.bottom_line - w.cline);
  898.             if (changed_line == w.rline)
  899.                line_on_screen = CURLINE;
  900.             else if (changed_line < w.rline && changed_line >= top_line) {
  901.                line_on_screen = NOTCURLINE;
  902.                w.cursor = cpb( w.cursor );
  903.                while (w.rline > changed_line) {
  904.                   w.cursor = find_prev( w.cursor );
  905.                   --w.rline;
  906.                   --w.cline;
  907.                }
  908.             } else if (changed_line > w.rline && changed_line <= bottom_line) {
  909.                line_on_screen = NOTCURLINE;
  910.                w.cursor = cpf( w.cursor );
  911.                while (w.rline < changed_line) {
  912.                   w.cursor = find_next( w.cursor );
  913.                   ++w.rline;
  914.                   ++w.cline;
  915.                }
  916.             }
  917.  
  918.             /*
  919.              * display the changed line if on screen
  920.              */
  921.             if (line_on_screen == NOTCURLINE)
  922.                update_line( &w );
  923.             else if (line_on_screen == CURLINE)
  924.                show_curl_line( &w );
  925.          }
  926.       }
  927.    }
  928.    file->dirty = FALSE;
  929. }
  930.  
  931.  
  932. /*
  933.  * Name:    show_curl_line
  934.  * Purpose: show current line in curl color
  935.  * Date:    January 16, 1992
  936.  * Passed:  window: current window
  937.  */
  938. void show_curl_line( WINDOW *window )
  939. {
  940. int text_color;
  941.  
  942.    text_color = g_display.text_color;
  943.    g_display.text_color = g_display.curl_color;
  944.    update_line( window );
  945.    g_display.text_color = text_color;
  946. }
  947.  
  948.  
  949. /*
  950.  * Name:    dup_window_info
  951.  * Purpose: Copy window info from one window pointer to another
  952.  * Date:    June 5, 1991
  953.  * Passed:  dw: destination window
  954.  *          sw: source window
  955.  */
  956. void dup_window_info( WINDOW *dw, WINDOW *sw )
  957. {
  958.    memcpy( dw, sw, sizeof( WINDOW ) );
  959. }
  960.  
  961.  
  962. /*
  963.  * Name:    addorsub_all_cursors
  964.  * Purpose: A change has been made - window->cursors in other windows must
  965.  *          be changed to reflect adding or subing of characters.
  966.  * Date:    June 5, 1991
  967.  * Passed:  window: current window
  968.  *          net_change:  number of bytes added or subtracted from a file
  969.  * Notes:   If a file has been changed, all of the memory pointers greater
  970.  *          than window->cursor must be adjusted by the number of characters
  971.  *          added or subtracted from the file pointed to by window.
  972.  *          If a file has been truncated in one window and there is another
  973.  *          window open to the same file and its current line is near the
  974.  *          end, the current line is reset to the last line of the file.
  975.  */
  976. void addorsub_all_cursors( WINDOW *window, long net_change )
  977. {
  978. register WINDOW *next;
  979. file_infos *file;
  980. file_infos *next_file;
  981.  
  982.    file = window->file_info;
  983.    next = g_status.window_list;
  984.    while (next != NULL) {
  985.       if (next != window) {
  986.          next_file = next->file_info;
  987.  
  988.          /*
  989.           * if next_file and file are the same, use rline to compare
  990.           * the current positions in the file.  DO NOT use cursor positions
  991.           * to compare current positions.  Text may or may not be inserted
  992.           * or deleted at the window->cursor position - we can un_copy_line
  993.           * at any position or line in the file not just the window->cursor
  994.           * line.
  995.           */
  996.          if (next_file == file) {
  997.             if (next->rline > window->rline)
  998.                next->cursor = addltop( net_change, next->cursor );
  999.          } else {
  1000.  
  1001.             /*
  1002.              * else next_file is not same as file.  see if the text
  1003.              * buffer for next_file is greater than file text buffer.
  1004.              */
  1005.             if (ptoul( next_file->start_text ) > ptoul( file->start_text ))
  1006.                next->cursor = addltop( net_change, next->cursor );
  1007.          }
  1008.       }
  1009.       next = next->next;
  1010.    }
  1011. }
  1012.  
  1013.  
  1014. /*
  1015.  * Name:    adjust_windows_cursor
  1016.  * Purpose: A change has been made - window->cursors in other windows must
  1017.  *          be changed to reflect adding or subing of characters.
  1018.  * Date:    June 5, 1991
  1019.  * Passed:  window: current window
  1020.  *          line_change: number of lines added or subtracted from a file
  1021.  * Notes:   If a file has been changed, all of the memory pointers greater
  1022.  *          than window->cursor must be adjusted by the number of characters
  1023.  *          added or subtracted from the file pointed to by window.
  1024.  *          If a file has been truncated in one window and there is another
  1025.  *          window open to the same file and its current line is near the
  1026.  *          end, the current line is reset to the last line of the file.
  1027.  */
  1028. void adjust_windows_cursor( WINDOW *window, int line_change )
  1029. {
  1030. register WINDOW *next;
  1031. register int reset;
  1032. text_ptr p;
  1033. int i;
  1034. file_infos *file;
  1035. file_infos *next_file;
  1036.  
  1037.    file = window->file_info;
  1038.    next = g_status.window_list;
  1039.    while (next != NULL) {
  1040.       if (next != window) {
  1041.          next_file = next->file_info;
  1042.          if (next_file == file) {
  1043.             reset = FALSE;
  1044.             if (ptoul( next->cursor ) > ptoul( file->end_text ))
  1045.                reset = END;
  1046.             else if (ptoul( next->cursor ) < ptoul( file->start_text ))
  1047.                reset = BEGIN;
  1048.             else if (next->rline > window->rline) {
  1049.                if (line_change) {
  1050.                   p = next->cursor;
  1051.                   if (line_change < 0) {
  1052.                      p = cpf( p );
  1053.                      for (i=line_change; i < 0 && p != NULL; i++)
  1054.                         p = find_next( p );
  1055.                      if (p != NULL)
  1056.                         next->cursor = p;
  1057.                      else
  1058.                         reset = END;
  1059.                   } else if (line_change > 0) {
  1060.                      p = cpb( p );
  1061.                      for (i=line_change; i > 0 && p != NULL; i--)
  1062.                         p = find_prev( p );
  1063.                      if (p != NULL)
  1064.                         next->cursor = p;
  1065.                      else
  1066.                         reset = BEGIN;
  1067.                   }
  1068.                }
  1069.             }
  1070.             if (reset) {
  1071.                if (reset == BEGIN) {
  1072.                   next->cursor = next_file->start_text;
  1073.                   next->rline = 1;
  1074.                   next->cline = next->top_line + next->ruler;
  1075.                } else {
  1076.                   next_file->end_text = cpb( next_file->end_text );
  1077.                   p = next_file->end_text - 1;
  1078.                   p = find_prev( p );
  1079.                   next->cursor = p != NULL ? p : next_file->end_text - 1;
  1080.                   next->rline  = next_file->length;
  1081.                }
  1082.                if (next->rline < (next->cline -(next->top_line+next->ruler-1)))
  1083.                   next->cline = (int)next->rline+(next->top_line+next->ruler)-1;
  1084.                file->dirty = NOT_LOCAL;
  1085.             }
  1086.          }
  1087.       }
  1088.       next = next->next;
  1089.    }
  1090. }
  1091.  
  1092.  
  1093. /*
  1094.  * Name:    adjust_start_end
  1095.  * Purpose: a file has been modified - must restore all start and end pointers
  1096.  * Date:    June 5, 1991
  1097.  * Passed:  mod_file:  pointer to modified file structure
  1098.  *          net_mod:   net modifications in the source file
  1099.  * Notes:   Go through the file list and adjust the start_text and end_text
  1100.  *          file pointers as needed.
  1101.  */
  1102. void adjust_start_end( file_infos *mod_file, long net_mod )
  1103. {
  1104. unsigned long mst;       /* mst == Mod_file->Start_Text */
  1105. unsigned long ost;       /* ost == Open_file_Start_Text */
  1106. register file_infos *open_file;
  1107.  
  1108.    mst = ptoul( mod_file->start_text );
  1109.    for (open_file=g_status.file_list; open_file != NULL;
  1110.              open_file=open_file->next) {
  1111.       ost = ptoul( open_file->start_text );
  1112.       if (ost == mst)
  1113.          mod_file->end_text = addltop( net_mod, mod_file->end_text );
  1114.       else if (ost > mst) {
  1115.          open_file->start_text = addltop( net_mod, open_file->start_text );
  1116.          open_file->end_text = addltop( net_mod, open_file->end_text );
  1117.       }
  1118.    }
  1119. }
  1120.  
  1121.  
  1122. /*
  1123.  * Name:    first_non_blank
  1124.  * Purpose: To find the column of the first non-blank character
  1125.  * Date:    June 5, 1991
  1126.  * Passed:  s:  the string to search
  1127.  * Returns: the first non-blank column
  1128.  */
  1129. int first_non_blank( char far *s )
  1130. {
  1131. register int count = 0;
  1132.  
  1133.    s = cpf( s );
  1134.    while (*s++ == ' ')
  1135.       ++count;
  1136.    return( count );
  1137. }
  1138.  
  1139.  
  1140. /*
  1141.  * Name:    is_line_blank
  1142.  * Purpose: is line empty or does it only contain spaces?
  1143.  * Date:    November 28, 1991
  1144.  * Passed:  s:  the string to search
  1145.  * Returns: TRUE if line is blank or FALSE if something is in line
  1146.  */
  1147. int is_line_blank( char far *s )
  1148. {
  1149.    s = cpf( s );
  1150.    while (*s == ' ')
  1151.       ++s;
  1152.    return( *s == '\n' || *s == CONTROL_Z );
  1153. }
  1154.  
  1155.  
  1156. /*
  1157.  * Name:    page_up
  1158.  * Purpose: To move the cursor one page up the window
  1159.  * Date:    June 5, 1991
  1160.  * Passed:  window:   information allowing access to the current window
  1161.  * Notes:   The cursor line is moved back the required number of lines
  1162.  *           towards the start of the file.
  1163.  *          If the start of the file is reached, then movement stops.
  1164.  */
  1165. void page_up( WINDOW *window )
  1166. {
  1167. int i;                          /* count of lines scanned */
  1168. text_ptr p, q;                  /* previous lines */
  1169. register WINDOW *win;          /* put window pointer in a register */
  1170.  
  1171.    win = window;
  1172.    un_copy_line( win->cursor, win, TRUE );
  1173.    if (win->rline != (win->cline - (win->top_line + win->ruler - 1))) {
  1174.       q = cpb( win->cursor );
  1175.       i = win->cline - (win->top_line + win->ruler - 1);
  1176.       if (( win->rline - i) < win->page) {
  1177.          i = (int)win->rline - (win->cline - (win->top_line + win->ruler - 1));
  1178.          for (; i>0; i--) {
  1179.             if ((p = find_prev( q )) != NULL)
  1180.                q = p;
  1181.          }
  1182.          win->rline = (win->cline-(win->top_line + win->ruler -1)) + win->page;
  1183.       } else {
  1184.          for (i=win->page; i>0; i--) {
  1185.             if ((p = find_prev( q )) != NULL)
  1186.                q = p;
  1187.          }
  1188.       }
  1189.       win->cursor = q;
  1190.       win->rline -= win->page;
  1191.       win->file_info->dirty = LOCAL;
  1192.    }
  1193.    sync( win );
  1194. }
  1195.  
  1196.  
  1197. /*
  1198.  * Name:    page_down
  1199.  * Purpose: To move the cursor one page down the window
  1200.  * Date:    June 5, 1991
  1201.  * Passed:  window:   information allowing access to the current window
  1202.  * Notes:   The cursor line is moved forwards the required number of lines
  1203.  *           towards the end of the file.
  1204.  *          If the end of the file is reached, then movement stops.
  1205.  */
  1206. void page_down( WINDOW *window )
  1207. {
  1208. int i, k;               /* count of lines scanned so far */
  1209. text_ptr p, q;          /* lines below cursor */
  1210. register WINDOW *win;  /* put window pointer in a register */
  1211.  
  1212.    win = window;
  1213.    un_copy_line( win->cursor, win, TRUE );
  1214.    q = cpf( win->cursor );
  1215.    k = win->cline - (win->top_line + win->ruler);
  1216.    for (i=0; i < win->page && *q != CONTROL_Z; i++, k++) {
  1217.       p = find_next( q );
  1218.       if (p != NULL)
  1219.          q = p;
  1220.       else
  1221.          break;
  1222.    }
  1223.    if (k >= win->page) {
  1224.       win->cursor = q;
  1225.       win->rline += i;
  1226.       win->cline = win->cline + i - win->page;
  1227.       win->file_info->dirty = LOCAL;
  1228.    }
  1229.    sync( win );
  1230. }
  1231.  
  1232.  
  1233. /*
  1234.  * Name:    scroll_down
  1235.  * Purpose: scroll window down one line
  1236.  * Date:    June 5, 1991
  1237.  * Passed:  window: information allowing access to the current window
  1238.  * Notes:   If there is a line to scroll_down, make the window LOCAL dirty.
  1239.  *          We have to redraw the screen anyway, so don't update here.
  1240.  */
  1241. void scroll_down( WINDOW *window )
  1242. {
  1243. text_ptr next;
  1244. register WINDOW *win;  /* put window pointer in a register */
  1245.  
  1246.    win = window;
  1247.    un_copy_line( win->cursor, win, TRUE );
  1248.    if (win->cline == win->top_line + win->ruler) {
  1249.       win->cursor = cpf( win->cursor );
  1250.       if ((next = find_next( win->cursor )) != NULL) {
  1251.          win->cursor = next;
  1252.          ++win->rline;
  1253.          win->file_info->dirty = LOCAL;
  1254.       }
  1255.    } else {
  1256.       --win->cline;
  1257.       win->file_info->dirty = LOCAL;
  1258.    }
  1259.    sync( win );
  1260. }
  1261.  
  1262.  
  1263. /*
  1264.  * Name:    scroll_up
  1265.  * Purpose: To scroll the window up one line
  1266.  * Date:    June 5, 1991
  1267.  * Passed:  window: information allowing access to the current window
  1268.  * Notes:   If this is the first page, then update screen here.  Else, make
  1269.  *             the window LOCAL dirty because we have to redraw screen.
  1270.  */
  1271. void scroll_up( WINDOW *window )
  1272. {
  1273. text_ptr prev;
  1274. register WINDOW *win;  /* put window pointer in a register */
  1275.  
  1276.    win = window;
  1277.    un_copy_line( win->cursor, win, TRUE );
  1278.    win->cursor = cpb( win->cursor );
  1279.    if (win->rline != 1) {
  1280.       if (win->rline == (win->cline - (win->top_line + win->ruler - 1))) {
  1281.          if (!mode.sync)
  1282.             update_line( win );
  1283.          if ((prev = find_prev( win->cursor )) != NULL)
  1284.             win->cursor = prev;
  1285.          --win->rline;
  1286.          --win->cline;
  1287.          if (!mode.sync)
  1288.             show_curl_line( win );
  1289.       } else {
  1290.          if (win->cline == win->bottom_line) {
  1291.             if ((prev = find_prev( win->cursor )) != NULL) {
  1292.                win->cursor = prev;
  1293.                --win->rline;
  1294.                win->file_info->dirty = LOCAL;
  1295.             }
  1296.          } else {
  1297.             ++win->cline;
  1298.             win->file_info->dirty = LOCAL;
  1299.          }
  1300.       }
  1301.    }
  1302.    sync( win );
  1303. }
  1304.  
  1305.  
  1306. /*
  1307.  * Name:    fixed_scroll_up
  1308.  * Purpose: To leave cursor on same logical line and scroll text up
  1309.  * Date:    September 1, 1991
  1310.  * Passed:  window: information allowing access to the current window
  1311.  * Notes:   If cursor is on first page then do not scroll.
  1312.  */
  1313. void fixed_scroll_up( WINDOW *window )
  1314. {
  1315. text_ptr prev;
  1316. register WINDOW *win;  /* put window pointer in a register */
  1317.  
  1318.    win = window;
  1319.    un_copy_line( win->cursor, win, TRUE );
  1320.    win->cursor = cpb( win->cursor );
  1321.  
  1322.    /*
  1323.     * see if cursor is on the first page. if it's not then fixed_scroll_up.
  1324.     */
  1325.    if (win->rline != (win->cline+1 - (win->top_line + win->ruler))) {
  1326.       if ((prev = find_prev( win->cursor )) != NULL) {
  1327.          win->cursor = prev;
  1328.          --win->rline;
  1329.          win->file_info->dirty = LOCAL;
  1330.       }
  1331.    }
  1332.    sync( win );
  1333. }
  1334.  
  1335.  
  1336. /*
  1337.  * Name:    fixed_scroll_down
  1338.  * Purpose: To leave cursor on same logical line and scroll text down
  1339.  * Date:    September 1, 1991
  1340.  * Passed:  window: information allowing access to the current window
  1341.  * Notes:   If cursor is on last line in file then do not scroll.
  1342.  */
  1343. void fixed_scroll_down( WINDOW *window )
  1344. {
  1345. text_ptr next;
  1346. register WINDOW *win;  /* put window pointer in a register */
  1347.  
  1348.    win = window;
  1349.    un_copy_line( win->cursor, win, TRUE );
  1350.    win->cursor = cpf( win->cursor );
  1351.    if ((next = find_next( win->cursor )) != NULL) {
  1352.       win->cursor = next;
  1353.       ++win->rline;
  1354.       win->file_info->dirty = LOCAL;
  1355.    }
  1356.    sync( win );
  1357. }
  1358.  
  1359.  
  1360. /*
  1361.  * Name:    file_file
  1362.  * Purpose: To file the current file to disk.
  1363.  * Date:    September 17, 1991
  1364.  * Passed:  window:   information allowing access to the current window
  1365.  */
  1366. void file_file( WINDOW *window )
  1367. {
  1368.    if (save_file( window ) == OK)
  1369.       finish( window );
  1370. }
  1371.  
  1372.  
  1373. /*
  1374.  * Name:    save_file
  1375.  * Purpose: To save the current file to disk.
  1376.  * Date:    June 5, 1991
  1377.  * Passed:  window:  information allowing access to the current window
  1378.  * Notes:   If anything goes wrong, then the modified flag is set.
  1379.  *          If the file is saved successfully, then modified flag is
  1380.  *           cleared.
  1381.  */
  1382. int  save_file( WINDOW *window )
  1383. {
  1384. char name[MAX_COLS]; /* name of file to be saved */
  1385. register file_infos *file;
  1386. int rc;
  1387.  
  1388.    un_copy_line( window->cursor, window, TRUE );
  1389.    file = window->file_info;
  1390.    if (file->modified == FALSE)
  1391.       return( OK );
  1392.    /*
  1393.     * set up file name
  1394.     */
  1395.    strcpy( name, file->file_name );
  1396.  
  1397.    /*
  1398.     * see if there was a file name - if not, then make the user
  1399.     *  supply one.
  1400.     */
  1401.    if (strlen( name ) == 0)
  1402.       rc = save_as_file( window );
  1403.    else {
  1404.       /*
  1405.        * save the file
  1406.        */
  1407.       rc = write_to_disk( window, name );
  1408.       if (rc != ERROR) {
  1409.          file->modified = FALSE;
  1410.          file->new_file = FALSE;
  1411.       } else
  1412.          error( WARNING, window->bottom_line,
  1413.                 "Error writing file or disk full" );
  1414.    }
  1415.    return( rc );
  1416. }
  1417.  
  1418.  
  1419. /*
  1420.  * Name:    save_backup
  1421.  * Purpose: To save a backup copy of the current file to disk.
  1422.  * Date:    June 5, 1991
  1423.  * Passed:  window:  information allowing access to the current window
  1424.  */
  1425. int  save_backup( WINDOW *window )
  1426. {
  1427.    /*
  1428.     * set up file name
  1429.     */
  1430.    return( write_to_disk( window, window->file_info->backup_fname ) );
  1431. }
  1432.  
  1433.  
  1434. /*
  1435.  * Name:    write_to_disk
  1436.  * Purpose: To write file from memory to disk
  1437.  * Date:    June 5, 1991
  1438.  * Passed:  window:  information allowing access to the current window
  1439.  */
  1440. int  write_to_disk( WINDOW *window, char *fname )
  1441. {
  1442. char name[MAX_COLS]; /* name of file to be saved */
  1443. char status_line[MAX_COLS+2]; /* status line at top of window */
  1444. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1445. register file_infos *file;
  1446. int rc;
  1447. int prompt_line;
  1448. int fattr;
  1449.  
  1450.    file = window->file_info;
  1451.    prompt_line = window->bottom_line;
  1452.  
  1453.    /*
  1454.     * set up file name
  1455.     */
  1456.    strcpy( name, fname );
  1457.  
  1458.    /*
  1459.     * save the file
  1460.     */
  1461.    save_screen_line( 0, prompt_line, line_buff );
  1462.    combine_strings( status_line, "Saving '", name, "'" );
  1463.    s_output( status_line, prompt_line, 0, g_display.message_color );
  1464.    eol_clear( strlen( status_line ), prompt_line, g_display.message_color );
  1465.    file->end_text = cpb( file->end_text );
  1466.    if ((rc = hw_save( name, file->start_text, file->end_text - mode.control_z,
  1467.                        NOTMARKED )) == ERROR) {
  1468.       if (ceh.flag != ERROR) {
  1469.          if (get_fattr( name, &fattr ) == OK && fattr & READ_ONLY)
  1470.             combine_strings( status_line, "file  '", name, "' is Read Only" );
  1471.          else
  1472.             combine_strings( status_line, "cannot write to '", name, "'" );
  1473.          error( WARNING, prompt_line, status_line );
  1474.       }
  1475.    }
  1476.    restore_screen_line( 0, prompt_line, line_buff );
  1477.    return( rc );
  1478. }
  1479.  
  1480.  
  1481. /*
  1482.  * Name:    save_as_file
  1483.  * Purpose: To save the current file to disk, but under a new name.
  1484.  * Date:    June 5, 1991
  1485.  * Passed:  window:  information allowing access to the current window
  1486.  */
  1487. int  save_as_file( WINDOW *window )
  1488. {
  1489. char name[MAX_COLS];            /* new name for file */
  1490. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1491. register file_infos *file;
  1492. int prompt_line;
  1493. int rc;
  1494. int fattr;
  1495. register WINDOW *win;          /* put window pointer in a register */
  1496.  
  1497.    win = window;
  1498.    un_copy_line( win->cursor, win, TRUE );
  1499.    /*
  1500.     * read in name
  1501.     */
  1502.    prompt_line = win->bottom_line;
  1503.    file = win->file_info;
  1504.    save_screen_line( 0, prompt_line, line_buff );
  1505.    name[0] = '\0';
  1506.    if ((rc = get_name( "New file name: ", prompt_line, name,
  1507.                  g_display.message_color )) == OK) {
  1508.  
  1509.        /*
  1510.         * make sure it is OK to overwrite any existing file
  1511.         */
  1512.       rc = get_fattr( name, &fattr );
  1513.       if (rc == OK) { /* file exists */
  1514.          set_prompt( "Overwrite existing file? (y/n): ", prompt_line );
  1515.          if (get_yn( ) != A_YES  ||  change_mode( name, prompt_line ) == ERROR)
  1516.             rc = ERROR;
  1517.       }
  1518.       if (rc != ERROR)
  1519.          rc = write_to_disk( win, name );
  1520.       if (rc == ERROR)
  1521.          error( WARNING, prompt_line, "Error writing file or disk full" );
  1522.    }
  1523.    restore_screen_line( 0, prompt_line, line_buff );
  1524.    return( rc );
  1525. }
  1526.  
  1527.  
  1528. /*
  1529.  * Name:    show_window_header
  1530.  * Purpose: show file stuff in window header
  1531.  * Date:    June 5, 1991
  1532.  * Passed:  window: information allowing access to the current window
  1533.  * Notes:   Clear line and display header in a lite bar
  1534.  */
  1535. void show_window_header( WINDOW *window )
  1536. {
  1537. char status_line[MAX_COLS+2];   /* status line at top of window */
  1538. register WINDOW *win;          /* put window pointer in a register */
  1539. int len;
  1540.  
  1541.    win = window;
  1542.    len = win->vertical ? win->end_col + 1 - win->start_col : win->end_col;
  1543.    memset( status_line, ' ', len );
  1544.    status_line[len] = '\0';
  1545.    s_output( status_line, win->top_line-1, win->start_col,g_display.head_color);
  1546.    show_window_number_letter( win );
  1547.    show_window_fname( win );
  1548.    show_size_name( win );
  1549.    show_size( win );
  1550.    show_line_col( win );
  1551. }
  1552.  
  1553.  
  1554. /*
  1555.  * Name:    show_window_number_letter
  1556.  * Purpose: show file number and letter of window in lite bar
  1557.  * Date:    June 5, 1991
  1558.  * Passed:  window:   information allowing access to the current window
  1559.  */
  1560. void show_window_number_letter( WINDOW *window )
  1561. {
  1562. int col;
  1563. char temp[10];
  1564. register WINDOW *win;  /* put window pointer in a register */
  1565.  
  1566.    win = window;
  1567.    col = win->start_col;
  1568.    s_output( "   ", win->top_line-1, col, g_display.head_color );
  1569.    itoa( win->file_info->file_no, temp, 10 );
  1570.    s_output( temp, win->top_line-1, strlen( temp ) > 1 ? col : col+1,
  1571.              g_display.head_color );
  1572.    c_output( win->letter, col+2, win->top_line-1, g_display.head_color );
  1573. }
  1574.  
  1575.  
  1576. /*
  1577.  * Name:    show_window_fname
  1578.  * Purpose: show file name in window header.
  1579.  * Date:    June 5, 1991
  1580.  * Passed:  window:  information allowing access to the current window
  1581.  * Notes:   Clear name field and display name in a lite bar
  1582.  */
  1583. void show_window_fname( WINDOW *window )
  1584. {
  1585. char status_line[MAX_COLS+2];   /* status line at top of window */
  1586. register int  fattr;
  1587. char *p;
  1588. register WINDOW *win;          /* put window pointer in a register */
  1589. int col;
  1590. int len;
  1591.  
  1592.    win = window;
  1593.    col = win->start_col;
  1594.    len = win->vertical ? 11 : FNAME_LENGTH;
  1595.    memset( status_line, ' ', len );
  1596.    status_line[len] = '\0';
  1597.    s_output( status_line, win->top_line-1, col+5, g_display.head_color );
  1598.    strcpy( status_line, win->file_info->file_name );
  1599.    p = status_line;
  1600.    if (win->vertical) {
  1601.       len = strlen( status_line );
  1602.       for (p=status_line+len;*(p-1) != ':' && *(p-1) != '\\' && p>status_line;)
  1603.          --p;
  1604.    } else {
  1605.       status_line[FNAME_LENGTH] = '\0';
  1606.       p = status_line;
  1607.    }
  1608.    s_output( p, win->top_line-1, col+5, g_display.head_color );
  1609.    if (!win->vertical) {
  1610.       fattr = win->file_info->file_attrib;
  1611.       p = status_line;
  1612.       *p++ = fattr & ARCHIVE   ? 'A' : '-';
  1613.       *p++ = fattr & SYSTEM    ? 'S' : '-';
  1614.       *p++ = fattr & HIDDEN    ? 'H' : '-';
  1615.       *p++ = fattr & READ_ONLY ? 'R' : '-';
  1616.       *p   = '\0';
  1617.       s_output( status_line, win->top_line-1, col+52, g_display.head_color );
  1618.    }
  1619. }
  1620.  
  1621.  
  1622. /*
  1623.  * Name:    show_size_name
  1624.  * Purpose: show ' s=' line lite bar header
  1625.  * Date:    June 5, 1991
  1626.  * Passed:  window:  information allowing access to the current window
  1627.  */
  1628. void show_size_name( WINDOW *window )
  1629. {
  1630.    if (!window->vertical)
  1631.       s_output( " s=", window->top_line-1, 57, g_display.head_color );
  1632. }
  1633.  
  1634.  
  1635. /*
  1636.  * Name:    show_size
  1637.  * Purpose: show number of lines in file
  1638.  * Date:    June 5, 1991
  1639.  * Passed:  window:  information allowing access to the current window
  1640.  */
  1641. void show_size( WINDOW *window )
  1642. {
  1643. char csize[20];
  1644.  
  1645.    if (!window->vertical) {
  1646.       s_output( "       ", window->top_line-1, 60, g_display.head_color );
  1647.       ltoa( window->file_info->length, csize, 10 );
  1648.       s_output( csize, window->top_line-1, 60, g_display.head_color );
  1649.    }
  1650. }
  1651.  
  1652.  
  1653. /*
  1654.  * Name:    quit
  1655.  * Purpose: To close the current window without saving the current file.
  1656.  * Date:    June 5, 1991
  1657.  * Passed:  window: information allowing access to the current window
  1658.  * Notes:   If the file has been modified but not saved, then the user is
  1659.  *           given a second chance before the changes are discarded.
  1660.  *          Note that this is only necessary if this is the last window
  1661.  *           that refers to the file. If another window still refers to
  1662.  *           the file, then the check can be left until later.
  1663.  */
  1664. void quit( WINDOW *window )
  1665. {
  1666. int prompt_line;
  1667. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  1668. register file_infos *file;
  1669. WINDOW *wp;
  1670. int count = 0;
  1671. int rc = OK;
  1672.  
  1673.    un_copy_line( window->cursor, window, TRUE );
  1674.    prompt_line = window->bottom_line;
  1675.    file = window->file_info;
  1676.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  1677.       if (wp->file_info == file && wp->visible)
  1678.          ++count;
  1679.    }
  1680.    if (file->modified && count == 1) {
  1681.       save_screen_line( 0, prompt_line, line_buff );
  1682.       set_prompt( "Abandon changes? (y/n): ", prompt_line );
  1683.       if (get_yn( ) == A_NO)
  1684.          rc = ERROR;
  1685.       restore_screen_line( 0, prompt_line, line_buff );
  1686.    }
  1687.  
  1688.    /*
  1689.     * remove window, allocate screen lines to other windows etc
  1690.     */
  1691.    if (rc == OK)
  1692.       finish( window );
  1693. }
  1694.  
  1695.  
  1696. /*
  1697.  * Name:    move_up
  1698.  * Purpose: To move the cursor up one line
  1699.  * Date:    June 5, 1991
  1700.  * Passed:  window:  information allowing access to the current window
  1701.  * Notes:   If the cursor is at the top of the window, then the file must
  1702.  *           be scrolled down.
  1703.  */
  1704. void move_up( WINDOW *window )
  1705. {
  1706. text_ptr p;             /* the previous line on the screen */
  1707. register WINDOW *win;  /* put window pointer in a register */
  1708. int at_top = FALSE;     /* is cline at top of screen? */
  1709.  
  1710.    win = window;
  1711.    un_copy_line( win->cursor, win, TRUE );
  1712.  
  1713.    /*
  1714.     * if no previous line, give up
  1715.     */
  1716.    win->cursor = cpb( win->cursor );
  1717.    if ((p = find_prev( win->cursor )) != NULL) {
  1718.       if (win->cline == win->top_line + win->ruler) {
  1719.          win->file_info->dirty = LOCAL;
  1720.          at_top = TRUE;
  1721.       }
  1722.       if (!at_top)
  1723.          update_line( win );
  1724.       win->cursor = p;
  1725.       --win->rline;           /* ALWAYS decrement line counter */
  1726.       if (!at_top) {
  1727.          --win->cline;    /* we aren't at top of screen - so move up */
  1728.          show_curl_line( win );
  1729.       }
  1730.    }
  1731.    sync( win );
  1732. }
  1733.  
  1734.  
  1735. /*
  1736.  * Name:    move_down
  1737.  * Purpose: To move the cursor down one line
  1738.  * Date:    June 5, 1991
  1739.  * Passed:  window:  information allowing access to the current window
  1740.  * Notes:   If the cursor is at the bottom of the window, then the file must
  1741.  *           be scrolled up.   If the cursor is at the bottom of the file,
  1742.  *           then scroll line up until it is at top of screen.
  1743.  */
  1744. void move_down( WINDOW *window )
  1745. {
  1746. text_ptr p;
  1747. register WINDOW *win;  /* put window pointer in a register */
  1748. int at_bottom = FALSE;  /* is cline at bottom of screen */
  1749.  
  1750.    win = window;
  1751.    un_copy_line( win->cursor, win, TRUE );
  1752.    if (win->cline == win->bottom_line) {
  1753.       win->file_info->dirty = LOCAL;
  1754.       at_bottom = TRUE;
  1755.    }
  1756.    if (!at_bottom)
  1757.       update_line( win );
  1758.    win->cursor = cpf( win->cursor );
  1759.    if ((p = find_next( win->cursor )) != NULL) {
  1760.       win->cursor = p;
  1761.       ++win->rline;                /* ALWAYS increment line counter */
  1762.       if (!at_bottom) {
  1763.          ++win->cline;     /* if not at bottom of screen move down */
  1764.          show_curl_line( win );
  1765.       }
  1766.    } else if (win->cline > win->top_line + win->ruler) {
  1767.       --win->cline;
  1768.       win->file_info->dirty = LOCAL;
  1769.    }
  1770.    sync( win );
  1771. }
  1772.  
  1773.  
  1774. /*
  1775.  * Name:    move_left
  1776.  * Purpose: To move the cursor left one character
  1777.  * Date:    June 5, 1991
  1778.  * Passed:  window:  information allowing access to the current window
  1779.  * Notes:   If the cursor is already at the left of the screen, then
  1780.  *           scroll horizontally if we're not at beginning of line.
  1781.  */
  1782. void move_left( WINDOW *window )
  1783. {
  1784. int new_ruler = FALSE;
  1785.  
  1786.    if (window->ccol > window->start_col) {
  1787.       show_ruler_char( window );
  1788.       --window->ccol;
  1789.       --window->rcol;
  1790.    } else if (window->ccol == window->start_col && window->rcol > 0) {
  1791.       --window->rcol;
  1792.       --window->bcol;
  1793.       window->file_info->dirty = LOCAL;
  1794.       new_ruler = TRUE;
  1795.    }
  1796.    sync( window );
  1797.    if (new_ruler) {
  1798.       make_ruler( window );
  1799.       show_ruler( window );
  1800.    }
  1801. }
  1802.  
  1803.  
  1804. /*
  1805.  * Name:    move_right
  1806.  * Purpose: To move the cursor right one character
  1807.  * Date:    June 5, 1991
  1808.  * Passed:  window:  information allowing access to the current window
  1809.  * Notes:   If the cursor is already at the right of the screen (logical
  1810.  *          column 80) then scroll horizontally right.
  1811.  */
  1812. void move_right( WINDOW *window )
  1813. {
  1814. int new_ruler = FALSE;
  1815.  
  1816.    if (window->rcol < g_display.line_length - 1) {
  1817.       if (window->ccol < window->end_col) {
  1818.          show_ruler_char( window );
  1819.          ++window->ccol;
  1820.          ++window->rcol;
  1821.       } else if (window->ccol == window->end_col) {
  1822.          ++window->rcol;
  1823.          ++window->bcol;
  1824.          window->file_info->dirty = LOCAL;
  1825.          new_ruler = TRUE;
  1826.       }
  1827.    }
  1828.    sync( window );
  1829.    if (new_ruler) {
  1830.       make_ruler( window );
  1831.       show_ruler( window );
  1832.    }
  1833. }
  1834.  
  1835.  
  1836. /*
  1837.  * Name:    scroll_left
  1838.  * Purpose: To scroll the screen left one character
  1839.  * Date:    January 5, 1992
  1840.  * Passed:  window:  information allowing access to the current window
  1841.  */
  1842. void scroll_left( WINDOW *window )
  1843. {
  1844.    if (window->bcol == 0) {
  1845.       if (window->ccol > window->start_col) {
  1846.          show_ruler_char( window );
  1847.          --window->ccol;
  1848.          --window->rcol;
  1849.       }
  1850.    } else if (window->bcol > 0 ) {
  1851. /*
  1852.  *  Scroll window left function:
  1853.  *      --window->bcol;
  1854.  *      if (window->ccol < g_display.ncols - 1)
  1855.  *         ++window->ccol;
  1856.  *      else
  1857.  *         --window->rcol;
  1858. */
  1859.       --window->bcol;
  1860.       --window->rcol;
  1861.       window->file_info->dirty = LOCAL;
  1862.       make_ruler( window );
  1863.       show_ruler( window );
  1864.    }
  1865.    sync( window );
  1866. }
  1867.  
  1868.  
  1869. /*
  1870.  * Name:    scroll_right
  1871.  * Purpose: To scroll the screen right one character
  1872.  * Date:    January 5, 1992
  1873.  * Passed:  window:  information allowing access to the current window
  1874.  */
  1875. void scroll_right( WINDOW *window )
  1876. {
  1877.    if (window->rcol < g_display.line_length - 1) {
  1878. /*
  1879.  *      scroll screen right function:
  1880.  *      if (window->ccol > 0)
  1881.  *         --window->ccol;
  1882.  *      else
  1883.  *         ++window->rcol;
  1884.  */
  1885.       ++window->rcol;
  1886.       ++window->bcol;
  1887.       window->file_info->dirty = LOCAL;
  1888.       make_ruler( window );
  1889.       show_ruler( window );
  1890.    }
  1891.    sync( window );
  1892. }
  1893.  
  1894.  
  1895. /*
  1896.  * Name:    word_left
  1897.  * Purpose: To move the cursor left one word
  1898.  * Date:    June 5, 1991
  1899.  * Passed:  window:  information allowing access to the current window
  1900.  * Notes:   Words are considered strings of letters, numbers and underscores,
  1901.  *          which must be separated by other characters.  After every 8000
  1902.  *          characters, check the pointer.
  1903.  */
  1904. void word_left( WINDOW *window )
  1905. {
  1906. text_ptr p;             /* text pointer */
  1907. int len;                /* length of current line */
  1908. register int c;         /* character at pointer */
  1909. register int check = 0;
  1910. WINDOW w;
  1911.  
  1912.    un_copy_line( window->cursor, window, TRUE );
  1913.    dup_window_info( &w, window );
  1914.    p = cpf( window->cursor );
  1915.    len = linelen( p );
  1916.    p += window->rcol > len ? len : window->rcol;
  1917.    p = cpb( p );
  1918.  
  1919.    for (c=*p; c != CONTROL_Z && myisalnum( c ); check++) {
  1920.       c = *--p;
  1921.       if (check > 8000) {
  1922.          p = cpb( p );
  1923.          check = 0;
  1924.       }
  1925.    }
  1926.    if (c != CONTROL_Z) {
  1927.       for (; c != CONTROL_Z && !myisalnum( c ); check++) {
  1928.          c = *--p;
  1929.          if (check > 8000) {
  1930.             p = cpb( p );
  1931.             check = 0;
  1932.          }
  1933.       }
  1934.       if (c != CONTROL_Z) {
  1935.          for (; c != CONTROL_Z && myisalnum( c ); check++) {
  1936.             c = *--p;
  1937.             if (check > 8000) {
  1938.                p = cpb( p );
  1939.                check = 0;
  1940.             }
  1941.          }
  1942.          find_adjust( window, ++p );
  1943.          if (w.rline != window->rline && !window->file_info->dirty) {
  1944.             update_line( &w );
  1945.             show_curl_line( window );
  1946.          }
  1947.          make_ruler( window );
  1948.          show_ruler( window );
  1949.       }
  1950.    }
  1951.    sync( window );
  1952. }
  1953.  
  1954.  
  1955. /*
  1956.  * Name:    word_right
  1957.  * Purpose: To move the cursor right one word
  1958.  * Date:    June 5, 1991
  1959.  * Passed:  window:  information allowing access to the current window
  1960.  * Notes:   Words are considered strings of letters, numbers and underscores,
  1961.  *           which must be separated by other characters.  After every 8000
  1962.  *           characters, check the pointer.
  1963.  */
  1964. void word_right( WINDOW *window )
  1965. {
  1966. int len;                /* length of current line */
  1967. text_ptr p;             /* text pointer */
  1968. register int c;         /* character at pointer */
  1969. register int check = 0;
  1970. WINDOW w;
  1971.  
  1972.    un_copy_line( window->cursor, window, TRUE );
  1973.    dup_window_info( &w, window );
  1974.    p = cpf( window->cursor );
  1975.    len = linelen( p );
  1976.    p += window->rcol > len ? len : window->rcol;
  1977.    for (c=*p; c != CONTROL_Z && myisalnum( c ); check++) {
  1978.       c = *++p;
  1979.       if (check > 8000) {
  1980.          p = cpf( p );
  1981.          check = 0;
  1982.       }
  1983.    }
  1984.    for (; c != CONTROL_Z && !myisalnum( c ); check++) {
  1985.       c = *++p;
  1986.       if (check > 8000) {
  1987.          p = cpf( p );
  1988.          check = 0;
  1989.       }
  1990.    }
  1991.    if (c != CONTROL_Z) {
  1992.       find_adjust( window, p );
  1993.       make_ruler( window );
  1994.       show_ruler( window );
  1995.    }
  1996.    if (w.rline != window->rline && !window->file_info->dirty) {
  1997.       update_line( &w );
  1998.       show_curl_line( window );
  1999.    }
  2000.    sync( window );
  2001. }
  2002.  
  2003.  
  2004. /*
  2005.  * Name:    center_window
  2006.  * Purpose: To place the current line or cursor in the center of a window.
  2007.  * Date:    June 5, 1991
  2008.  * Passed:  window: information allowing access to the current window
  2009.  */
  2010. void center_window( WINDOW *window )
  2011. {
  2012. int center;
  2013. int center_line;
  2014. int diff;
  2015. register file_infos *file;
  2016. int i;
  2017. register WINDOW *win;          /* put window pointer in a register */
  2018.  
  2019.    win = window;
  2020.    file = win->file_info;
  2021.    center = (win->bottom_line + 1 - win->top_line) / 2 - win->ruler;
  2022.    center_line = win->top_line + win->ruler + center;
  2023.    diff = center_line - win->cline;
  2024.    if (g_status.command == CenterWindow) {
  2025.       un_copy_line( win->cursor, win, TRUE );
  2026.       if (diff > 0) {
  2027.          if (win->rline + diff <= file->length) {
  2028.             update_line( win );
  2029.             win->cline += diff;
  2030.             win->rline += diff;
  2031.             win->cursor = cpf( win->cursor );
  2032.             for (i=0; i<diff; i++)
  2033.                win->cursor = find_next( win->cursor );
  2034.             show_curl_line( win );
  2035.          }
  2036.       } else if (diff < 0) {
  2037.          update_line( win );
  2038.          win->cline += diff;
  2039.          win->rline += diff;
  2040.          win->cursor = cpb( win->cursor );
  2041.          for (i=diff; i<0; i++)
  2042.             win->cursor = find_prev( win->cursor );
  2043.          show_curl_line( win );
  2044.       }
  2045.    } else if (g_status.command == CenterLine) {
  2046.       if (diff > 0) {
  2047.          win->cline += diff;
  2048.          if ((long)(win->cline+1 - (win->top_line + win->ruler)) > win->rline)
  2049.             win->cline = (win->top_line + win->ruler) - 1 + (int)win->rline;
  2050.          file->dirty = LOCAL;
  2051.       } else if (diff < 0) {
  2052.          win->cline = win->cline + diff;
  2053.          file->dirty = LOCAL;
  2054.       }
  2055.    }
  2056.    sync( win );
  2057. }
  2058.  
  2059.  
  2060. /*
  2061.  * Name:    horizontal_screen_right
  2062.  * Purpose: To move the cursor one screen to the right
  2063.  * Date:    September 13, 1991
  2064.  * Passed:  window:  information allowing access to the current window
  2065.  * Notes:   Add 80 columns to the real cursor.  If the cursor is past the
  2066.  *          maximum line length then move it back.
  2067.  */
  2068. void horizontal_screen_right( WINDOW *window )
  2069. {
  2070.    window->rcol += (window->end_col + 1 - window->start_col);
  2071.    if (window->rcol >= MAX_LINE_LENGTH)
  2072.       window->rcol = MAX_LINE_LENGTH - 1;
  2073.    else {
  2074.       window->bcol += (window->end_col + 1 - window->start_col);
  2075.       window->file_info->dirty = LOCAL;
  2076.    }
  2077.    check_virtual_col( window, window->rcol, window->ccol );
  2078.    sync( window );
  2079.    make_ruler( window );
  2080.    show_ruler( window );
  2081. }
  2082.  
  2083.  
  2084. /*
  2085.  * Name:    horizontal_screen_left
  2086.  * Purpose: To move the cursor one screen to the left
  2087.  * Date:    September 13, 1991
  2088.  * Passed:  window:  information allowing access to the current window
  2089.  * Notes:   Subtract screen width from the real cursor.  If the cursor is less
  2090.  *          than zero then see if bcol is zero.  If bcol is not zero then make
  2091.  *          bcol zero.
  2092.  */
  2093. void horizontal_screen_left( WINDOW *window )
  2094. {
  2095. int screen_width;
  2096.  
  2097.    screen_width = window->end_col + 1 - window->start_col;
  2098.    if (window->rcol - screen_width < 0) {
  2099.       if (window->bcol != 0) {
  2100.          window->bcol = 0;
  2101.          window->file_info->dirty = LOCAL;
  2102.       }
  2103.    } else {
  2104.       window->rcol -= screen_width;
  2105.       window->bcol -= screen_width;
  2106.       if (window->bcol < 0)
  2107.          window->bcol = 0;
  2108.       window->file_info->dirty = LOCAL;
  2109.    }
  2110.    check_virtual_col( window, window->rcol, window->ccol );
  2111.    sync( window );
  2112.    make_ruler( window );
  2113.    show_ruler( window );
  2114. }
  2115.  
  2116.  
  2117. /*
  2118.  * Name:    set_marker
  2119.  * Purpose: To set file marker
  2120.  * Date:    December 28, 1991
  2121.  * Passed:  window:  information allowing access to the current window
  2122.  */
  2123. void set_marker( WINDOW *window )
  2124. {
  2125. register MARKER  *marker;       /* put the marker in a register */
  2126.  
  2127.    marker = &window->file_info->marker[g_status.command - SetMark1];
  2128.    marker->rline  = window->rline;
  2129.    marker->rcol   = window->rcol;
  2130.    marker->ccol   = window->ccol;
  2131.    marker->bcol   = window->bcol;
  2132.    marker->marked = TRUE;
  2133. }
  2134.  
  2135.  
  2136. /*
  2137.  * Name:    goto_marker
  2138.  * Purpose: To goto a file marker
  2139.  * Date:    December 28, 1991
  2140.  * Passed:  window:  information allowing access to the current window
  2141.  */
  2142. void goto_marker( WINDOW *window )
  2143. {
  2144. int m;
  2145. file_infos *file;
  2146. char *q = "Marker   not set in this file";
  2147. text_ptr p;
  2148. long i;
  2149. long number;
  2150. MARKER *marker;
  2151. register WINDOW *win;  /* put window pointer in a register */
  2152.  
  2153.    win = window;
  2154.    m = g_status.command - GotoMark1;
  2155.    file = win->file_info;
  2156.    marker = &file->marker[m];
  2157.    if (marker->marked) {
  2158.       un_copy_line( win->cursor, win, TRUE );
  2159.       file->dirty = LOCAL;
  2160.       if (marker->rline > file->length)
  2161.          marker->rline = file->length;
  2162.       number = marker->rline;
  2163.       p = win->cursor;
  2164.       i = win->rline;
  2165.       if (number < win->rline) {
  2166.          p = cpb( p );
  2167.          for (; i>number; i--)
  2168.             p = find_prev( p );
  2169.       } else {
  2170.          p = cpf( p );
  2171.          for (; i<number; i++)
  2172.             p = find_next( p );
  2173.       }
  2174.       win->cursor = p;
  2175.       win->rline  = marker->rline;
  2176.       win->rcol   = marker->rcol;
  2177.       win->ccol   = marker->ccol;
  2178.       win->bcol   = marker->bcol;
  2179.       if (win->rline < (win->cline - ((win->top_line + win->ruler) - 1)))
  2180.          win->cline = (int)win->rline + (win->top_line + win->ruler) - 1;
  2181.       check_virtual_col( win, win->rcol, win->ccol );
  2182.       make_ruler( window );
  2183.       show_ruler( window );
  2184.    } else {
  2185.       if (m == 9)
  2186.          m = -1;
  2187.       *(q + 7) = (char)('0' + m + 1);
  2188.       error( WARNING, win->bottom_line, q );
  2189.    }
  2190. }
  2191.  
  2192.  
  2193. /*
  2194.  * Name:    change_fattr
  2195.  * Purpose: To change the file attributes
  2196.  * Date:    December 31, 1991
  2197.  * Passed:  window:  information allowing access to the current window
  2198.  */
  2199. void change_fattr( WINDOW *window )
  2200. {
  2201. char name[MAX_COLS];              /* new name for file */
  2202. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  2203. file_infos *file;
  2204. WINDOW *wp;
  2205. int prompt_line;
  2206. register int ok;
  2207. unsigned char fattr;
  2208. char *s;
  2209.  
  2210.    prompt_line = window->bottom_line;
  2211.    save_screen_line( 0, prompt_line, line_buff );
  2212.    name[0] = '\0';
  2213.    if ((ok = get_name( "Enter new file attributes, \"AaSsHhRr\" : ",
  2214.                      prompt_line, name, g_display.message_color )) == OK) {
  2215.       if (*name != '\0') {
  2216.          fattr = 0;
  2217.          s = name;
  2218.          while (ok = *s++) {
  2219.             switch (ok) {
  2220.                case 'a' :
  2221.                case 'A' :
  2222.                   fattr |= ARCHIVE;
  2223.                   break;
  2224.                case 's' :
  2225.                case 'S' :
  2226.                   fattr |= SYSTEM;
  2227.                   break;
  2228.                case 'h' :
  2229.                case 'H' :
  2230.                   fattr |= HIDDEN;
  2231.                   break;
  2232.                case 'r' :
  2233.                case 'R' :
  2234.                   fattr |= READ_ONLY;
  2235.                   break;
  2236.             }
  2237.          }
  2238.          file = window->file_info;
  2239.          if (set_fattr( file->file_name, fattr ))
  2240.             error( WARNING, prompt_line, "New file attributes not set" );
  2241.          else {
  2242.             file->file_attrib = fattr;
  2243.             for (wp=g_status.window_list; wp!=NULL; wp=wp->next) {
  2244.                if (wp->file_info == file && wp->visible)
  2245.                   show_window_fname( wp );
  2246.             }
  2247.          }
  2248.       }
  2249.    }
  2250.    restore_screen_line( 0, prompt_line, line_buff );
  2251. }
  2252.