home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / progc / tde11.arj / UTILS.C < prev    next >
Encoding:
C/C++ Source or Header  |  1991-07-11  |  44.8 KB  |  1,544 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
  34.  *
  35.  * This modification of Douglas Thomson's code is released into the
  36.  * public domain, Frank Davis.  You may distribute it freely.
  37.  */
  38.  
  39. #include "tdestr.h"
  40. #include "common.h"
  41. #include "define.h"
  42. #include "tdefunc.h"
  43. #ifdef __TURBOC__
  44.   #include <dir.h>        /* for making temporary file names etc */
  45. #endif
  46. #if defined( __MSC__ )
  47.    #include <dos.h>
  48.    #include <io.h>
  49. #endif
  50.  
  51.  
  52. /*
  53.  * Name:    myisalnum
  54.  * Purpose: To determine whether or not a character is part of a "word",
  55.  *           which in languages like Pascal means a letter, digit or
  56.  *           underscore.
  57.  * Date:    October 1, 1989
  58.  * Passed:  c: the character to be tested
  59.  * Returns: TRUE if c is an alphanumeric or '_' character, FALSE otherwise
  60.  */
  61. int  myisalnum( c )
  62. int c;
  63. {
  64. int rc;
  65.  
  66.    rc = FALSE;
  67.    if (isalnum( c ) || (c == '_'))
  68.       rc = TRUE;
  69.    return( rc );
  70. }
  71.  
  72.  
  73. /*
  74.  * Name:    check_virtual_col
  75.  * Purpose: make sure real column is displayed on screen
  76.  * Date:    June 5, 1991
  77.  * Passed:  window: current window
  78.  *          rcol: real column of cursor
  79.  *          ccol: current or logical column of cursor
  80.  */
  81. void check_virtual_col( window, rcol, ccol )
  82. windows *window;
  83. int rcol, ccol;
  84. {
  85. int bcol, ncols;
  86. file_infos *file;
  87.  
  88.    file = window->file_info;
  89.    bcol = window->bcol;
  90.    ncols = g_display.ncols - 1;
  91.  
  92.    /*
  93.     * is logical column past end of screen?
  94.     */
  95.    if (ccol > ncols) {
  96.       ccol = ccol - bcol;
  97.       if (ccol > ncols) {
  98.          ccol = ncols;
  99.          bcol = rcol - ccol;
  100.          file->dirty = LOCAL;
  101.       }
  102.  
  103.    /*
  104.     * is logical column behind start of screen?
  105.     */
  106.    } else if (ccol < 0) {
  107.       if (bcol >= -ccol)
  108.          bcol += ccol;
  109.       ccol = 0;
  110.       file->dirty = LOCAL;
  111.  
  112.    /*
  113.     * is current column < base column?
  114.     */
  115.    } else if (rcol < bcol) {
  116.       ccol = rcol;
  117.       bcol = 0;
  118.       if (ccol > ncols) {
  119.          bcol = rcol - ncols;
  120.          ccol = rcol - bcol;
  121.       }
  122.       file->dirty = LOCAL;
  123.    }
  124.  
  125.    /*
  126.     * current column + base column MUST equal real column
  127.     */
  128.    if (ccol + bcol != rcol) {
  129.       if (bcol < 0)
  130.          bcol = rcol;
  131.       ccol = rcol - bcol;
  132.       if (ccol > ncols) {
  133.          bcol = rcol - ncols;
  134.          ccol = rcol - bcol;
  135.       }
  136.       file->dirty = LOCAL;
  137.    }
  138.    window->bcol = bcol;
  139.    window->ccol = ccol;
  140.    window->rcol = rcol;
  141. }
  142.  
  143.  
  144. /*
  145.  * Name:    copy_line
  146.  * Purpose: To copy the cursor line, if necessary, into the current line
  147.  *           buffer, so that changes can be made efficiently.
  148.  * Date:    June 5, 1991
  149.  * Passed:  text_line: line to be copied to line buffer
  150.  *          line: line to display error message
  151.  * Notes:   See un_copy_line, the reverse operation.  Terminate text strings
  152.  *          with CONTROL_Z.  DO NOT use the C library string functions on
  153.  *          text in g_status.line_buff.
  154.  */
  155. void copy_line( text_line, line )
  156. text_ptr text_line;
  157. int line;
  158. {
  159. text_ptr d, s;     /* destination and source of copy */
  160. int len;
  161.  
  162.    if (g_status.copied == FALSE) {
  163.       g_status.copied = TRUE;
  164.       /*
  165.        * copy the cursor line to the line buffer
  166.        */
  167.       d = g_status.line_buff;
  168.       g_status.buff_line = text_line;
  169.       s = cpf( text_line );
  170.       len = linelen( s );
  171.       if (s[len] == '\n')
  172.          ++len;
  173.       if (len >= g_display.line_length) {
  174.          len = g_display.line_length;
  175.          error( WARNING, line,  "line buffer overflow - line truncated!" );
  176.       }
  177.       memmove( d, s, len );
  178.       d[len] = CONTROL_Z;
  179.    }
  180. }
  181.  
  182.  
  183. /*
  184.  * Name:    un_copy_line
  185.  * Purpose: To copy the cursor line, if necessary, from the current line
  186.  *           buffer, shifting the main text to make the right amount of
  187.  *           room.
  188.  * Date:    June 5, 1991
  189.  * Passed:  test_line:  pointer to location in file to copy line buffer
  190.  *          window:  pointer to current window info
  191.  *          del_trailing:  delete the trailing blanks at eol? TRUE or FALSE
  192.  * Notes:   For some functions, trailing spaces should not be removed when
  193.  *           returning the line buffer to the main text.  The JoinLine function
  194.  *           is a good example.  We need to leave trailing space so when we
  195.  *           join lines - the current line will extend at least up to
  196.  *           the column of the cursor.  We allow need to leave trailing space
  197.  *           during BOX block operations.
  198.  *          See copy_line, the reverse operation.
  199.  */
  200. void un_copy_line( text_line, window, del_trailing )
  201. text_ptr text_line;
  202. windows *window;
  203. int del_trailing;
  204. {
  205. text_ptr source; /* source for block move and for copying buffer line */
  206. text_ptr dest;   /* destination for block move and copy */
  207. long number;     /* length of block move */
  208. int space;
  209. int len;         /* length of current line buffer text */
  210. int curs_len;    /* length of cursor line */
  211. int prompt_line;
  212. int i;
  213. file_infos *file;
  214.  
  215.    if (g_status.copied == TRUE) {
  216.       /*
  217.        * work out the lengths of the old cursor line (including the \n if any)
  218.        *  and the new current line buffer text.
  219.        */
  220.       prompt_line = window->bottom_line;
  221.       text_line = cpf( text_line );
  222.       curs_len = linelen( text_line );
  223.       if (text_line[curs_len] == '\n')
  224.          ++curs_len;
  225.       if (del_trailing) {
  226.          len = linelen( g_status.line_buff );
  227.          i = find_CONTROL_Z( g_status.line_buff ) + 1;
  228.          i -= len;
  229.          for (source=g_status.line_buff+len-1; len > 0; len--, source--) {
  230.             if (*source == ' ')
  231.                memmove( source, source+1, i );
  232.             else
  233.                break;
  234.          }
  235.       }
  236.       len = find_CONTROL_Z( g_status.line_buff );
  237.       space = len - curs_len;
  238.  
  239.       /*
  240.        * if the main text buffer has run out of space, then only part of the
  241.        *  current line can be moved back into the main buffer. Warn the user
  242.        *  that some of the current line has been lost
  243.        */
  244.       if (ptoul( g_status.end_mem ) + (long)space >= ptoul( g_status.max_mem )) {
  245.          error( WARNING, prompt_line, "buffer full, part line truncated" );
  246.          len = curs_len + (int) (ptoul( g_status.max_mem ) -
  247.                                  ptoul( g_status.end_mem ));
  248.       }
  249.  
  250.       /*
  251.        * move text to either make room for the extra characters in the new
  252.        *  line, or else close up the gap.
  253.        */
  254.       source = text_line + curs_len;
  255.       dest = addltop( (long)space, source );
  256.       number = ptoul( g_status.end_mem ) - ptoul( source );
  257.       hw_move( dest, source, number );
  258.       g_status.end_mem = addltop( (long)space, g_status.end_mem );
  259.  
  260.       /*
  261.        * now copy the line buffer into the space just created
  262.        */
  263.       memmove( text_line, g_status.line_buff, len );
  264.       g_status.copied = FALSE;
  265.       file = window->file_info;
  266.       file->modified = TRUE;
  267.       adjust_start_end( file, space );
  268.       addorsub_all_cursors( window, space );
  269.       show_avail_mem( );
  270.    }
  271. }
  272.  
  273.  
  274. /*
  275.  * Name:    load_file
  276.  * Purpose: To read in a given file to the end of the main text buffer.
  277.  * Date:    June 5, 1991
  278.  * Passed:  name:   path name of file to be read
  279.  * Returns: OK if file read successfully
  280.  *          ERROR if any problem (such as out of buffer space)
  281.  */
  282. int  load_file( name )
  283. char *name;
  284. {
  285. int line;                       /* line on screen to display prompt */
  286. int rc;
  287.  
  288.    rc = OK;
  289.    line = g_display.nlines;
  290.  
  291.    /*
  292.     * make sure this gets set properly even if there is no file!
  293.     */
  294.    g_status.temp_end = g_status.end_mem;
  295.  
  296.    rc = hw_load( name, g_status.end_mem, g_status.max_mem,
  297.            &g_status.temp_end, line );
  298.    return( rc );
  299. }
  300.  
  301. /*
  302.  * Name:    set_prompt
  303.  * Purpose: To display a prompt, highlighted, at the bottom of the screen.
  304.  * Date:    October 1, 1989
  305.  * Passed:  prompt: prompt to be displayed
  306.  *          line:  line on which to display prompt
  307.  */
  308. void set_prompt( prompt, line )
  309. char *prompt;
  310. int line;
  311. {
  312.    /*
  313.     * work out where the answer should go
  314.     */
  315.    g_status.prompt_col = strlen( prompt );
  316.    g_status.prompt_line = line;
  317.  
  318.    /*
  319.     * output the prompt
  320.     */
  321.    s_output( prompt, line, 0, g_display.message_color );
  322.    eol_clear( g_status.prompt_col, line, g_display.message_color );
  323.  
  324.    /*
  325.     * ensure the cursor is in the right place
  326.     */
  327.    xygoto( g_status.prompt_col, g_status.prompt_line );
  328. }
  329.  
  330. /*
  331.  * Name:    get_name
  332.  * Purpose: To prompt the user, and read the string the user enters in
  333.  *           response.
  334.  * Date:    October 1, 1989
  335.  * Passed:  prompt: prompt to offer the user
  336.  *          line:   no. of lines up from the bottom of the screen
  337.  *          name:   default answer
  338.  *          color:  color to display prompt
  339.  * Returns: name:   user's answer
  340.  *          OK if user entered something
  341.  *          ERROR if user aborted the command
  342.  * Notes:   Editing of the line is supported.
  343.  */
  344. int get_name( prompt, line, name, color )
  345. char *prompt;
  346. int line;
  347. char *name;
  348. int color;
  349. {
  350. int col;                /* cursor column for answer */
  351. int c;                  /* character user just typed */
  352. char *cp;               /* cursor position in answer */
  353. char *answer;           /* user's answer */
  354. int first = TRUE;       /* first character typed */
  355. int len;                /* length of answer */
  356. int plen;               /* length of prompt */
  357. int func;               /* function of key pressed */
  358. char *p;                /* for copying text in answer */
  359. char buffer[MAX_COLS+2];/* line on which name is being entered */
  360. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  361. int normal;
  362.  
  363.    /*
  364.     * set up prompt and default
  365.     */
  366.    strcpy( buffer, prompt );
  367.    plen = strlen( prompt );
  368.    answer = buffer + plen;
  369.    strcpy( answer, name );
  370.  
  371.    /*
  372.     * let user edit default into desired string
  373.     */
  374.    len = strlen( answer );
  375.    col = strlen( buffer );
  376.    cp = answer + len;
  377.    c = 0;
  378.    normal = g_display.text_color;
  379.    save_screen_line( 0, line, line_buff );
  380.    s_output( buffer, line, 0, color );
  381.    eol_clear( col, line, normal );
  382.    for (func=0; func != AbortCommand  &&  func != Rturn;) {
  383.       xygoto( col, line );
  384.       c = getkey( );
  385.       func = getfunc( c );
  386.       switch (func) {
  387.          case ToggleSearchCase :
  388.             if (bm.search_case == IGNORE)
  389.                bm.search_case = MATCH;
  390.             else
  391.                bm.search_case = IGNORE;
  392.             show_search_case( );
  393.             break;
  394.          case Rturn :
  395.             answer[len] = '\0';
  396.             strcpy( name, answer );
  397.             /*
  398.              * finished
  399.              */
  400.             break;
  401.          case BackSpace :
  402.             /*
  403.              * delete to left of cursor
  404.              */
  405.             if (cp > answer) {
  406.                for (p=cp-1; p < answer+len; p++) {
  407.                   *p = *(p+1);
  408.                }
  409.                --len;
  410.                --col;
  411.                --cp;
  412.                c_output( ' ', plen+len, line, normal);
  413.                s_output( cp, line, col, color );
  414.                *(answer + len) = '\0';
  415.             }
  416.             break;
  417.          case DeleteChar :
  418.             /*
  419.              * delete char under cursor
  420.              */
  421.             if (*cp) {
  422.                for (p=cp; p < answer+len; p++) {
  423.                   *p = *(p+1);
  424.                }
  425.                --len;
  426.                c_output( ' ', plen+len, line, normal);
  427.                s_output( cp, line, col, color );
  428.                *(answer + len) = '\0';
  429.             }
  430.             break;
  431.          case DeleteLine :
  432.             /*
  433.              * delete current line
  434.              */
  435.             col = plen;
  436.             cp = answer;
  437.             *cp = '\0';
  438.             len = 0;
  439.             eol_clear( col, line, normal );
  440.             break;
  441.          case RestoreString :
  442.             /*
  443.              * restore original line
  444.              */
  445.             strcpy( answer, name );
  446.             len = strlen( answer );
  447.             col = plen + len;
  448.             cp = answer + len;
  449.             s_output( cp, line, col, color );
  450.             break;
  451.          case CharLeft :
  452.             /*
  453.              * move cursor left
  454.              */
  455.             if (cp > answer) {
  456.                col--;
  457.                cp--;
  458.             }
  459.             break;
  460.          case CharRight :
  461.             /*
  462.              * move cursor right
  463.              */
  464.             if (*cp) {
  465.                col++;
  466.                cp++;
  467.              }
  468.              break;
  469.          case BegOfLine :
  470.             /*
  471.              * move cursor to start of line
  472.              */
  473.             col = plen;
  474.             cp = answer;
  475.             break;
  476.          case EndOfLine :
  477.             /*
  478.              * move cursor to end of line
  479.              */
  480.             col = plen + len;
  481.             cp = answer + len;
  482.             break;
  483.          default :
  484.             if (c < 0x100) {
  485.                /*
  486.                 * insert character at cursor
  487.                 */
  488.                if (first) {
  489.                   /*
  490.                    * delete previous answer
  491.                    */
  492.                   col = plen;
  493.                   cp = answer;
  494.                   *cp = '\0';
  495.                   len = 0;
  496.                   eol_clear( col, line, normal );
  497.                }
  498.  
  499.                /*
  500.                 * insert new character
  501.                 */
  502.                if (col < g_display.ncols-1) {
  503.                   if (*cp == '\0') {
  504.                      ++len;
  505.                      *(answer + len) = '\0';
  506.                   }
  507.                   *cp = c;
  508.                   c_output( c, col, line, color );
  509.                   ++cp;
  510.                   ++col;
  511.                }
  512.             }
  513.             break;
  514.       }
  515.       first = FALSE;
  516.    }
  517.    restore_screen_line( 0, line, line_buff );
  518.    if (func == AbortCommand)
  519.       c = ERROR;
  520.    else
  521.       c = OK;
  522.    return( c );
  523. }
  524.  
  525.  
  526. /*
  527.  * Name:    get_yn
  528.  * Purpose: To input a response of yes or no.
  529.  * Date:    October 1, 1989
  530.  * Returns: the user's answer (A_??? - see tdestr.h)
  531.  */
  532. int  get_yn( )
  533. {
  534. int c;   /* the user's response */
  535. int rc;  /* return code */
  536. int func;
  537.  
  538.    xygoto( g_status.prompt_col, g_status.prompt_line );
  539.    for (rc=-1; rc<0;) {
  540.       c = getkey( );
  541.       func = getfunc( c );
  542.       if (func == AbortCommand)
  543.          rc = A_ABORT;
  544.       else {
  545.          switch ( c ) {
  546.             case 'Y':
  547.             case 'y':
  548.                rc = A_YES;
  549.                break;
  550.             case 'N':
  551.             case 'n':
  552.                rc = A_NO;
  553.                break;
  554.          }
  555.       }
  556.    }
  557.    return( rc );
  558. }
  559.  
  560.  
  561. /*
  562.  * Name:    get_oa
  563.  * Purpose: To input a response of overwrite or append.
  564.  * Date:    October 1, 1989
  565.  * Returns: the user's answer (A_??? - see tdestr.h)
  566.  */
  567. int get_oa( )
  568. {
  569. int c;   /* the user's response */
  570. int rc;  /* return code */
  571. int func;
  572.  
  573.    rc = 0;
  574.    while (rc != AbortCommand && rc != A_OVERWRITE && rc != A_APPEND) {
  575.       xygoto( g_status.prompt_col, g_status.prompt_line );
  576.       c = getkey( );
  577.       func = getfunc( c );
  578.       if (c < 0x100)
  579.          c_output( c, g_display.col, g_display.line, g_display.message_color );
  580.       if (func == AbortCommand)
  581.          rc = A_ABORT;
  582.       switch ( c ) {
  583.          case 'O':
  584.          case 'o':
  585.             rc = A_OVERWRITE;
  586.             break;
  587.          case 'A':
  588.          case 'a':
  589.             rc = A_APPEND;
  590.             break;
  591.       }
  592.    }
  593.    return( rc );
  594. }
  595.  
  596.  
  597. /*
  598.  * Name:    display_current_window
  599.  * Purpose: display text in current window
  600.  * Date:    June 5, 1991
  601.  * Passed:  window: current window
  602.  * Notes:   use a temporary window structure, "w", to do the dirty work.
  603.  */
  604. void display_current_window( window )
  605. windows *window;
  606. {
  607. text_ptr prev, p;      /* successive lines above the cursor */
  608. int count;          /* number of lines updated so far */
  609. int number;         /* number of lines visible in window */
  610. int attr;
  611. int i;
  612. windows w;
  613.  
  614.    /*
  615.     * work out how many lines need to be displayed
  616.     */
  617.    number = window->bottom_line - (window->top_line - 1);
  618.  
  619.    /*
  620.     * display the required number of lines, starting from the
  621.     *  cursor line
  622.     */
  623.    dup_window_info( &w, window );
  624.    w.cursor = cpb( w.cursor );
  625.    count = window->cline - window->top_line;
  626.    for (i=count; i>0; i--) {
  627.       p = find_prev( w.cursor );
  628.       if (p) {
  629.          w.cursor = p;
  630.          --w.cline;
  631.          --w.rline;
  632.       }
  633.    }
  634.    attr = g_display.text_color;
  635.    w.cursor = cpf( w.cursor );
  636.    for (i=number; i>0; i--) {
  637.       if (w.cursor) {
  638.          update_line( &w );
  639.          w.cursor = find_next( w.cursor );
  640.       } else
  641.          eol_clear( 0, w.cline, COLOR_TEXT );
  642.       ++w.cline;
  643.       ++w.rline;
  644.    }
  645. }
  646.  
  647.  
  648. /*
  649.  * Name:    redraw_screen
  650.  * Purpose: display all visible windows if some change was GLOBAL
  651.  * Date:    June 5, 1991
  652.  * Passed:  window: current window
  653.  */
  654. void redraw_screen( window )
  655. windows *window;
  656. {
  657. windows *above;             /* window above current */
  658. windows *below;             /* window below current */
  659.  
  660.    /*
  661.     * display the current window
  662.     */
  663.    redraw_current_window( window );
  664.  
  665.    /*
  666.     * now update all the other windows
  667.     */
  668.    above = below = window;
  669.    while (above->prev || below->next) {
  670.       if (above->prev) {
  671.          above = above->prev;
  672.          redraw_current_window( above );
  673.       }
  674.       if (below->next) {
  675.          below = below->next;
  676.          redraw_current_window( below );
  677.       }
  678.    }
  679.    window->file_info->dirty = FALSE;
  680.    show_modes( );
  681.    show_file_count( g_status.file_count );
  682.    show_avail_mem( );
  683.    show_indent_mode( );
  684.    show_search_case( );
  685. }
  686.  
  687.  
  688. /*
  689.  * Name:    redraw_current_window
  690.  * Purpose: redraw all info in this window
  691.  * Date:    July 13, 1991
  692.  * Passed:  window: current window
  693.  */
  694. void redraw_current_window( window )
  695. windows *window;
  696. {
  697.  
  698.    /*
  699.     * display the current window
  700.     */
  701.    if (window->visible) {
  702.       display_current_window( window );
  703.       show_window_header( window->file_info->file_name, window );
  704.       show_size_name( window );
  705.       show_size( window );
  706.       show_line_col( window );
  707.    }
  708. }
  709.  
  710.  
  711. /*
  712.  * Name:    show_changed_line
  713.  * Purpose: Only one line was changed in file, just show it
  714.  * Date:    June 5, 1991
  715.  * Passed:  window: current window
  716.  */
  717. void show_changed_line( window )
  718. windows *window;
  719. {
  720. windows *above;             /* window above current */
  721. windows *below;             /* window below current */
  722. windows w;
  723. long changed_line;
  724. long top_line, bottom_line;
  725. int line_on_screen;
  726. file_infos *file;
  727.  
  728.    file = window->file_info;
  729.    if (file->dirty == LOCAL || file->dirty == GLOBAL)
  730.       update_line( window );
  731.    changed_line = window->rline;
  732.  
  733.    /*
  734.     * now update the line in all other windows
  735.     */
  736.    if (file->dirty != LOCAL) {
  737.       above = below = window;
  738.       while (above->prev || below->next) {
  739.          if (above->prev) {
  740.             above = above->prev;
  741.             dup_window_info( &w, above );
  742.          } else if (below->next) {
  743.             below = below->next;
  744.             dup_window_info( &w, below );
  745.          }
  746.          if (w.file_info == window->file_info && w.visible) {
  747.             line_on_screen = FALSE;
  748.             top_line = w.rline - (w.cline - w.top_line);
  749.             bottom_line = w.rline + (w.bottom_line - w.cline);
  750.             if (changed_line == w.rline)
  751.                line_on_screen = TRUE;
  752.             else if (changed_line < w.rline && changed_line >= top_line) {
  753.                line_on_screen = TRUE;
  754.                w.cursor = cpb( w.cursor );
  755.                while (w.rline > changed_line) {
  756.                   w.cursor = find_prev( w.cursor );
  757.                   --w.rline;
  758.                   --w.cline;
  759.                }
  760.             } else if (changed_line > w.rline && changed_line <= bottom_line) {
  761.                line_on_screen = TRUE;
  762.                w.cursor = cpf( w.cursor );
  763.                while (w.rline < changed_line) {
  764.                   w.cursor = find_next( w.cursor );
  765.                   ++w.rline;
  766.                   ++w.cline;
  767.                }
  768.             }
  769.             if (line_on_screen)
  770.                update_line( &w );
  771.          }
  772.       }
  773.    }
  774.    file->dirty = FALSE;
  775. }
  776.  
  777.  
  778. /*
  779.  * Name:    dup_window_info
  780.  * Purpose: Copy window info from one window pointer to another
  781.  * Date:    June 5, 1991
  782.  * Passed:  dw: destination window
  783.  *          sw: source window
  784.  */
  785. void dup_window_info( dw, sw )
  786. windows *dw, *sw;
  787. {
  788.    memcpy( dw, sw, sizeof( windows ) );
  789. }
  790.  
  791.  
  792. /*
  793.  * Name:    adjust_windows_cursor
  794.  * Purpose: A change has been made - window->cursors in other windows must
  795.  *          be changed to reflect adding or subing of characters.
  796.  * Date:    June 5, 1991
  797.  * Passed:  window: current window
  798.  *          net_change:  number of bytes added or subtracted from a file
  799.  * Notes:   If a file has been changed, all of the memory pointers greater
  800.  *          than window->cursor must be adjusted by the number of characters
  801.  *          added or subtracted from the file pointed to by window.
  802.  *          If a file has been truncated in one window and there is another
  803.  *          window open to the same file and its current line is near the
  804.  *          end, the current line is reset to the last line of the file.
  805.  */
  806. void addorsub_all_cursors( window, net_change )
  807. windows *window;
  808. long net_change;
  809. {
  810. windows *next;
  811. int reset;
  812. text_ptr p;
  813. int i;
  814. file_infos *file;
  815. file_infos *next_file;
  816.  
  817.    file = window->file_info;
  818.    next = g_status.window_list;
  819.    while (next != NULL) {
  820.       if (next != window) {
  821.          next_file = next->file_info;
  822.          if (next_file == file) {
  823.             if (next->rline > window->rline)
  824.                next->cursor = addltop( net_change, next->cursor );
  825.          } else {
  826.             if (ptoul( next_file->start_text ) > ptoul( file->start_text ))
  827.                next->cursor = addltop( net_change, next->cursor );
  828.          }
  829.       }
  830.       next = next->next;
  831.    }
  832. }
  833.  
  834.  
  835. /*
  836.  * Name:    adjust_windows_cursor
  837.  * Purpose: A change has been made - window->cursors in other windows must
  838.  *          be changed to reflect adding or subing of characters.
  839.  * Date:    June 5, 1991
  840.  * Passed:  window: current window
  841.  *          line_change: number of lines added or subtracted from a file
  842.  * Notes:   If a file has been changed, all of the memory pointers greater
  843.  *          than window->cursor must be adjusted by the number of characters
  844.  *          added or subtracted from the file pointed to by window.
  845.  *          If a file has been truncated in one window and there is another
  846.  *          window open to the same file and its current line is near the
  847.  *          end, the current line is reset to the last line of the file.
  848.  */
  849. void adjust_windows_cursor( window, line_change )
  850. windows *window;
  851. int  line_change;
  852. {
  853. windows *next;
  854. int reset;
  855. text_ptr p;
  856. int i;
  857. file_infos *file;
  858. file_infos *next_file;
  859.  
  860.    file = window->file_info;
  861.    next = g_status.window_list;
  862.    while (next != NULL) {
  863.       if (next != window) {
  864.          next_file = next->file_info;
  865.          if (next_file == file) {
  866.             reset = FALSE;
  867.             if (ptoul( next->cursor ) > ptoul( file->end_text ))
  868.                reset = END;
  869.             else if (ptoul( next->cursor ) < ptoul( file->start_text ))
  870.                reset = BEGIN;
  871.             else if (next->rline > window->rline) {
  872.                if (line_change) {
  873.                   p = next->cursor;
  874.                   if (line_change < 0) {
  875.                      p = cpf( p );
  876.                      for (i=line_change; i < 0 && p != NULL; i++)
  877.                         p = find_next( p );
  878.                      if (p != NULL)
  879.                         next->cursor = p;
  880.                      else
  881.                         reset = END;
  882.                   } else if (line_change > 0) {
  883.                      p = cpb( p );
  884.                      for (i=line_change; i > 0 && p != NULL; i--)
  885.                         p = find_prev( p );
  886.                      if (p != NULL)
  887.                         next->cursor = p;
  888.                      else
  889.                         reset = BEGIN;
  890.                   }
  891.                }
  892.             }
  893.             if (reset) {
  894.                if (reset == BEGIN) {
  895.                   next->cursor = next_file->start_text;
  896.                   next->rline = 1;
  897.                   next->cline = next->top_line;
  898.                } else {
  899.                   next_file->end_text = cpb( next_file->end_text );
  900.                   p = next_file->end_text - 1;
  901.                   p = find_prev( p );
  902.                   if (p != NULL)
  903.                     next->cursor = p;
  904.                   else
  905.                      next->cursor = next_file->end_text - 1;
  906.                   next->rline  = next_file->length;
  907.                }
  908.                if (next->rline < (next->cline - (next->top_line - 1)))
  909.                   next->cline = next->rline + next->top_line - 1;
  910.                file->dirty = NOT_LOCAL;
  911.             }
  912.          }
  913.       }
  914.       next = next->next;
  915.    }
  916. }
  917.  
  918.  
  919. /*
  920.  * Name:    adjust_start_end
  921.  * Purpose: a file has been modified - must restore all start and end pointers
  922.  * Date:    June 5, 1991
  923.  * Passed:  mod:  pointer to modified file structure
  924.  *          net_mod:  net modifications in the source file
  925.  * Notes:   Go through the file list and adjust the start_text and end_text
  926.  *          file pointers as needed.
  927.  */
  928. void adjust_start_end( mod_file, net_mod )
  929. file_infos *mod_file;
  930. long net_mod;
  931. {
  932. unsigned long mst, ost;
  933. file_infos *open_file;
  934.  
  935.    mst = ptoul( mod_file->start_text );
  936.    for (open_file=g_status.file_list; open_file != NULL;
  937.              open_file=open_file->next) {
  938.       ost = ptoul( open_file->start_text );
  939.       if (ost == mst)
  940.          mod_file->end_text = addltop( net_mod, mod_file->end_text );
  941.       else if (ost > mst) {
  942.          open_file->start_text = addltop( net_mod, open_file->start_text );
  943.          open_file->end_text = addltop( net_mod, open_file->end_text );
  944.       }
  945.    }
  946. }
  947.  
  948.  
  949. /*
  950.  * Name:    first_non_blank
  951.  * Purpose: To find the column in which the first non-blank character in
  952.  *           the string occurs.
  953.  * Date:    June 5, 1991
  954.  * Passed:  s:  the string to search
  955.  * Returns: the first non-blank column
  956.  */
  957. int first_non_blank( s )
  958. char *s;
  959. {
  960. int count = 0;
  961.  
  962.    s = cpf( s );
  963.    while (*s++ == ' ')
  964.       ++count;
  965.    return( count );
  966. }
  967.  
  968. /*
  969.  * Name:    page_up
  970.  * Purpose: To move the cursor one page up the window (probably more
  971.  *           intuitive to think of the text being moved down)
  972.  * Date:    June 5, 1991
  973.  * Passed:  window:   information allowing access to the current window
  974.  * Notes:   The cursor line is moved back the required number of lines
  975.  *           towards the start of the file.
  976.  *          If the start of the file is reached, then the movement stops.
  977.  */
  978. void page_up( window )
  979. windows *window;
  980. {
  981. int i;           /* count of lines scanned */
  982. text_ptr p, q;   /* previous lines */
  983.  
  984.    un_copy_line( window->cursor, window, TRUE );
  985.    if (window->rline != (window->cline - (window->top_line-1))) {
  986.       q = cpb( window->cursor );
  987.       i = window->cline - (window->top_line-1);
  988.       if (( window->rline - i) < window->page) {
  989.          i = window->rline - (window->cline - (window->top_line-1));
  990.          for (; i>0; i--) {
  991.             if ((p = find_prev( q )) != NULL)
  992.                q = p;
  993.          }
  994.          window->rline = (window->cline-(window->top_line-1)) + window->page;
  995.       } else {
  996.          for (i=window->page; i>0; i--) {
  997.             if ((p = find_prev( q )) != NULL)
  998.                q = p;
  999.          }
  1000.       }
  1001.       window->cursor = q;
  1002.       window->rline -= window->page;
  1003.       window->file_info->dirty = LOCAL;
  1004.    }
  1005. }
  1006.  
  1007. /*
  1008.  * Name:    page_down
  1009.  * Purpose: To move the cursor one page down the window (probably more
  1010.  *           intuitive to think of the text being moved up)
  1011.  * Date:    June 5, 1991
  1012.  * Passed:  window:   information allowing access to the current window
  1013.  * Notes:   The cursor line is moved forwards the required number of lines
  1014.  *           towards the end of the file.
  1015.  *          If the end of the file is reached, then the movement stops.
  1016.  */
  1017. void page_down( window )
  1018. windows *window;
  1019. {
  1020. int i, k;          /* count of lines scanned so far */
  1021. text_ptr p, q;     /* lines below cursor */
  1022.  
  1023.    un_copy_line( window->cursor, window, TRUE );
  1024.    q = cpf( window->cursor );
  1025.    k = window->cline - window->top_line;
  1026.    for (i=0; i < window->page && *q != CONTROL_Z; i++, k++) {
  1027.       p = find_next( q );
  1028.       if (p != NULL)
  1029.          q = p;
  1030.       else
  1031.          break;
  1032.    }
  1033.    if (k >= window->page) {
  1034.       window->cursor = q;
  1035.       window->rline += i;
  1036.       window->cline = window->cline + i - window->page;
  1037.       window->file_info->dirty = LOCAL;
  1038.    }
  1039. }
  1040.  
  1041. /*
  1042.  * Name:    scroll_down
  1043.  * Purpose: To make the necessary changes after the user has given the
  1044.  *           command to scroll down the screen.
  1045.  * Date:    June 5, 1991
  1046.  * Passed:  window: information allowing access to the current window
  1047.  * Notes:   Normally, we can just delete the top line on the window, and
  1048.  *           then move the cursor up one line (so the cursor remains at
  1049.  *           the same position in the file).
  1050.  *          However, if the cursor was already on the top line of the
  1051.  *           window, then the cursor must be moved down a line first.
  1052.  */
  1053. void scroll_down( window )
  1054. windows *window;
  1055. {
  1056. text_ptr next;
  1057.  
  1058.    un_copy_line( window->cursor, window, TRUE );
  1059.    window->cursor = cpf( window->cursor );
  1060.    if (window->cline == window->top_line) {
  1061.       if ((next = find_next( window->cursor )) != NULL)
  1062.          window->cursor = next;
  1063.       else
  1064.          return;
  1065.       ++window->cline;
  1066.       ++window->rline;
  1067.    }
  1068.    --window->cline;
  1069.    window->file_info->dirty = LOCAL;
  1070. }
  1071.  
  1072. /*
  1073.  * Name:    scroll_up
  1074.  * Purpose: To make the necessary changes after the user has given the
  1075.  *           command to scroll up the screen.
  1076.  * Date:    June 5, 1991
  1077.  * Passed:  window: information allowing access to the current window
  1078.  * Notes:   Normally, we can just insert one line at the top of the window,
  1079.  *           and then move the cursor down one line (so the cursor remains at
  1080.  *           the same position in the file).
  1081.  *          However, if the cursor was already on the bottom line of the
  1082.  *           window, then the cursor must be moved up a line first.
  1083.  */
  1084. void scroll_up( window )
  1085. windows *window;
  1086. {
  1087. text_ptr prev;
  1088.  
  1089.    un_copy_line( window->cursor, window, TRUE );
  1090.    window->cursor = cpb( window->cursor );
  1091.    if (window->rline != 1) {
  1092.       if (window->rline == (window->cline - (window->top_line -1))) {
  1093.          if ((prev = find_prev( window->cursor )) != NULL)
  1094.             window->cursor = prev;
  1095.          --window->rline;
  1096.          --window->cline;
  1097.       } else {
  1098.          if (window->cline == window->bottom_line) {
  1099.             if ((prev = find_prev( window->cursor )) != NULL)
  1100.                window->cursor = prev;
  1101.             else
  1102.                return;
  1103.             --window->cline;
  1104.             --window->rline;
  1105.          }
  1106.          ++window->cline;
  1107.          window->file_info->dirty = LOCAL;
  1108.       }
  1109.    }
  1110. }
  1111.  
  1112. /*
  1113.  * Name:    save_file
  1114.  * Purpose: To save the current file to disk.
  1115.  * Date:    June 5, 1991
  1116.  * Passed:  window:   information allowing access to the current window
  1117.  * Notes:   If anything goes wrong, then the modified flag is set.
  1118.  *          If the file is saved successfully, then modified flag is
  1119.  *           cleared.
  1120.  */
  1121. void save_file( window )
  1122. windows *window;
  1123. {
  1124. char name[MAX_COLS]; /* name of file to be saved */
  1125. char status_line[MAX_COLS+2]; /* status line at top of window */
  1126. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1127. file_infos *file;
  1128. int rc;
  1129. int prompt_line;
  1130.  
  1131.    un_copy_line( window->cursor, window, TRUE );
  1132.    prompt_line = window->bottom_line;
  1133.  
  1134.    /*
  1135.     * set up file name and location of various flags
  1136.     */
  1137.    file = window->file_info;
  1138.    strcpy( name, file->file_name );
  1139.  
  1140.    /*
  1141.     * see if there was a file name - if not, then make the user
  1142.     *  supply one.
  1143.     */
  1144.    if (strlen( name ) == 0) {
  1145.       save_as_file( window );
  1146.       return;
  1147.    }
  1148.  
  1149.    /*
  1150.     * save the file
  1151.     */
  1152.    save_screen_line( 0, prompt_line, line_buff );
  1153.    combine_strings( status_line, "Saving '", name, "'" );
  1154.    s_output( status_line, prompt_line, 0, g_display.message_color );
  1155.    eol_clear( strlen( status_line ), prompt_line, g_display.message_color );
  1156.    file->end_text = cpb( file->end_text );
  1157.    if ((rc = hw_save( name, file->start_text, file->end_text-1, NOTMARKED,
  1158.                       prompt_line )) == ERROR) {
  1159.       combine_strings( status_line, "cannot write to '", name, "'" );
  1160.       error( WARNING, prompt_line, status_line );
  1161.    }
  1162.    restore_screen_line( 0, prompt_line, line_buff );
  1163.    if (rc != ERROR) {
  1164.       file->modified = FALSE;
  1165.       file->new_file = FALSE;
  1166.    }
  1167. }
  1168.  
  1169. /*
  1170.  * Name:    save_as_file
  1171.  * Purpose: To save the current file to disk, but under a new name.
  1172.  * Date:    June 5, 1991
  1173.  * Passed:  window:   information allowing access to the current window
  1174.  */
  1175. void save_as_file( window )
  1176. windows *window;
  1177. {
  1178. char name[MAX_COLS];              /* new name for file */
  1179. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  1180. char status_line[MAX_COLS+2]; /* status line at top of window */
  1181. file_infos *file;
  1182. int prompt_line;
  1183. int ok;
  1184.  
  1185.    un_copy_line( window->cursor, window, TRUE );
  1186.    /*
  1187.     * read in name, no default
  1188.     */
  1189.    prompt_line = window->bottom_line;
  1190.    file = window->file_info;
  1191.    save_screen_line( 0, prompt_line, line_buff );
  1192.    name[0] = '\0';
  1193.    if (get_name( "New file name: ", prompt_line, name,
  1194.                  g_display.message_color ) == OK) {
  1195.  
  1196.        /*
  1197.         * make sure it is OK to overwrite any existing file
  1198.         */
  1199.       ok = TRUE;
  1200.       if (hw_fattrib( name ) != ERROR) { /* file exists */
  1201.          set_prompt( "Overwrite existing file? (y/n): ", prompt_line );
  1202.          if (get_yn( ) != A_YES  ||  hw_unlink( name, prompt_line ) == ERROR)
  1203.             ok = FALSE;
  1204.       }
  1205.       if (ok == TRUE) {
  1206.          combine_strings( status_line, "Saving '", name, "'" );
  1207.          s_output( status_line, prompt_line, 0, g_display.message_color );
  1208.          eol_clear( strlen( status_line ), prompt_line,
  1209.                     g_display.message_color );
  1210.          file->end_text = cpb( file->end_text );
  1211.          if (hw_save( name, file->start_text, file->end_text-1, NOTMARKED,
  1212.                       prompt_line ) == ERROR) {
  1213.             combine_strings( status_line, "cannot write to '", name, "'" );
  1214.             error( WARNING, prompt_line, status_line );
  1215.          } else
  1216.  
  1217.             /*
  1218.              * record that file is saved and not yet modified again
  1219.              */
  1220.             file->modified = FALSE;
  1221.       }
  1222.    }
  1223.    restore_screen_line( 0, prompt_line, line_buff );
  1224. }
  1225.  
  1226.  
  1227. /*
  1228.  * Name:    show_window_header
  1229.  * Purpose: To save the current file to disk, but under a new name.
  1230.  * Date:    June 5, 1991
  1231.  * Passed:  name:   name of file being edited
  1232.  *          window:   information allowing access to the current window
  1233.  * Notes:   Clear line and display file name in a lite bar
  1234.  */
  1235. void show_window_header( name, window )
  1236. char *name;
  1237. windows *window;
  1238. {
  1239. char status_line[MAX_COLS+2]; /* status line at top of window */
  1240. char *p, *q;            /* for setting up status line */
  1241.  
  1242.    memset( status_line, ' ', MAX_COLS );
  1243.    status_line[MAX_COLS] = '\0';
  1244.    q = name;
  1245.    p = status_line + 1;
  1246.    while (*q)
  1247.       *p++ = *q++;
  1248.    s_output( status_line, window->top_line-1, 0, g_display.head_color );
  1249. }
  1250.  
  1251.  
  1252. /*
  1253.  * Name:    show_size_name
  1254.  * Purpose: show 'size' line lite bar header
  1255.  * Date:    June 5, 1991
  1256.  * Passed:  window:   information allowing access to the current window
  1257.  */
  1258. void show_size_name( window )
  1259. windows *window;
  1260. {
  1261. char size_line[MAX_COLS+2]; /* status line at top of window */
  1262.  
  1263.    strcpy( size_line, " size = " );
  1264.    s_output( size_line, window->top_line-1, 49, g_display.head_color );
  1265. }
  1266.  
  1267.  
  1268. /*
  1269.  * Name:    show_size
  1270.  * Purpose: show number of lines in file
  1271.  * Date:    June 5, 1991
  1272.  * Passed:  window:   information allowing access to the current window
  1273.  */
  1274. void show_size( window )
  1275. windows *window;
  1276. {
  1277. char size_line[MAX_COLS+2]; /* status line at top of window */
  1278. char csize[20];
  1279. char *p, *q;            /* for setting up status line */
  1280.  
  1281.    strcpy( size_line, "        " );
  1282.    p = size_line;
  1283.    ltoa( window->file_info->length, csize, 10 );
  1284.    q = csize;
  1285.    while (*q)
  1286.       *p++ = *q++;
  1287.    *p++ = ' ';
  1288.    *p = '\0';
  1289.    s_output( size_line, window->top_line-1, 57, g_display.head_color );
  1290. }
  1291.  
  1292.  
  1293. /*
  1294.  * Name:    quit
  1295.  * Purpose: To close the current window without saving the current file.
  1296.  * Date:    June 5, 1991
  1297.  * Passed:  window: information allowing access to the current window
  1298.  *          stop:   pointer to editor stop variable
  1299.  * Notes:   If the file has been modified but not saved, then the user is
  1300.  *           given a second chance before the changes are discarded.
  1301.  *          Note that this is only necessary if this is the last window
  1302.  *           that refers to the file. If another window still refers to
  1303.  *           the file, then the check can be left until later.
  1304.  */
  1305. void quit( window, stop )
  1306. windows *window;
  1307. int *stop;
  1308. {
  1309. int prompt_line;
  1310. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  1311. file_infos *file;
  1312. windows *wp;
  1313. int count = 0;
  1314.  
  1315.    un_copy_line( window->cursor, window, TRUE );
  1316.    prompt_line = window->bottom_line;
  1317.    file = window->file_info;
  1318.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  1319.       if (wp->file_info == file && wp->visible)
  1320.          ++count;
  1321.    }
  1322.    if (file->modified && count == 1) {
  1323.       save_screen_line( 0, prompt_line, line_buff );
  1324.       set_prompt( "Abandon changes? (y/n): ", prompt_line );
  1325.       if (get_yn( ) != A_YES) {
  1326.          restore_screen_line( 0, prompt_line, line_buff );
  1327.          return;
  1328.       }
  1329.    }
  1330.  
  1331.    /*
  1332.     * remove window, allocate screen lines to other windows etc
  1333.     */
  1334.    finish( window, stop );
  1335. }
  1336.  
  1337.  
  1338. /*
  1339.  * Name:    move_up
  1340.  * Purpose: To move the cursor one line up the screen.
  1341.  * Date:    June 5, 1991
  1342.  * Passed:  window:   information allowing access to the current window
  1343.  * Notes:   If the cursor is at the top of the window, then the file must
  1344.  *           be scrolled down.
  1345.  *          If the cursor is already on the first line of the file, then
  1346.  *           this command can be ignored.
  1347.  */
  1348. void move_up( window )
  1349. windows *window;
  1350. {
  1351. text_ptr p;   /* the previous line on the screen */
  1352.  
  1353.    un_copy_line( window->cursor, window, TRUE );
  1354.    /*
  1355.     * if no previous line, give up
  1356.     */
  1357.    window->cursor = cpb( window->cursor );
  1358.    if ((p = find_prev( window->cursor )) != NULL) {
  1359.       window->cursor = p;
  1360.       --window->rline;           /* ALWAYS decrement line counter */
  1361.       if (window->cline == window->top_line) {
  1362.          window_scroll_down( window->top_line, window->bottom_line );
  1363.          update_line( window );
  1364.       } else
  1365.          --window->cline;    /* we aren't at top of screen - so move up */
  1366.    }
  1367. }
  1368.  
  1369.  
  1370. /*
  1371.  * Name:    move_down
  1372.  * Purpose: To move the cursor one line down the screen.
  1373.  * Date:    June 5, 1991
  1374.  * Passed:  window:   information allowing access to the current window
  1375.  * Notes:   If the cursor is at the bottom of the window, then the file must
  1376.  *           be scrolled up.   If the cursor is at the bottom of the file,
  1377.  *           then scroll up until cursor is at top of screen.
  1378.  */
  1379. void move_down( window )
  1380. windows *window;
  1381. {
  1382. text_ptr p;
  1383. int bottom_line;
  1384.  
  1385.    un_copy_line( window->cursor, window, TRUE );
  1386.    bottom_line = window->bottom_line;
  1387.    window->cursor = cpf( window->cursor );
  1388.    if ((p = find_next( window->cursor )) != NULL) {
  1389.       window->cursor = p;
  1390.       ++window->rline;                /* ALWAYS increment line counter */
  1391.       if (window->cline == bottom_line) {
  1392.          window_scroll_up( window->top_line, bottom_line );
  1393.          update_line( window );
  1394.       } else
  1395.          ++window->cline;     /* if not at bottom of screen move down */
  1396.    } else if (window->cline > window->top_line) {
  1397.       --window->cline;
  1398.       window_scroll_up_eof( window->top_line, bottom_line );
  1399.    }
  1400. }
  1401.  
  1402.  
  1403. /*
  1404.  * Name:    move_left
  1405.  * Purpose: To move the cursor one character to the left
  1406.  * Date:    June 5, 1991
  1407.  * Passed:  window:   information allowing access to the current window
  1408.  * Notes:   If the cursor is already at the left of the screen, then
  1409.  *           scroll horizontally if we're not at beginning of line.
  1410.  */
  1411. void move_left( window )
  1412. windows *window;
  1413. {
  1414.    if (window->ccol > 0) {
  1415.       --window->ccol;
  1416.       --window->rcol;
  1417.    } else if (window->ccol == 0 && window->rcol > 0) {
  1418.       --window->rcol;
  1419.       --window->bcol;
  1420.       window->file_info->dirty = LOCAL;
  1421.    }
  1422. }
  1423.  
  1424.  
  1425. /*
  1426.  * Name:    move_right
  1427.  * Purpose: To move the cursor one character to the right
  1428.  * Date:    June 5, 1991
  1429.  * Passed:  window:   information allowing access to the current window
  1430.  * Notes:   If the cursor is already at the right of the screen (logical
  1431.  *          column 80) then scroll horizontally right.
  1432.  */
  1433. void move_right( window )
  1434. windows *window;
  1435. {
  1436. int max_col;
  1437.  
  1438.    max_col = g_display.ncols - 1;
  1439.    if (window->ccol < max_col) {
  1440.       ++window->ccol;
  1441.       ++window->rcol;
  1442.    } else if (window->ccol == max_col && window->rcol < g_display.line_length) {
  1443.       ++window->rcol;
  1444.       ++window->bcol;
  1445.       window->file_info->dirty = LOCAL;
  1446.    }
  1447. }
  1448.  
  1449.  
  1450. /*
  1451.  * Name:    word_left
  1452.  * Purpose: To move the cursor one word to the left.
  1453.  * Date:    June 5, 1991
  1454.  * Passed:  window:   information allowing access to the current window
  1455.  * Notes:   Words are considered strings of letters, numbers and underscores,
  1456.  *          which must be separated by other characters.
  1457.  */
  1458. void word_left( window )
  1459. windows *window;
  1460. {
  1461. text_ptr p;   /* text pointer */
  1462. int len;      /* length of current line */
  1463. int c;        /* character at pointer */
  1464. int check = 0;
  1465.  
  1466.    un_copy_line( window->cursor, window, TRUE );
  1467.    p = cpf( window->cursor );
  1468.    len = linelen( p );
  1469.    if (window->rcol > len)
  1470.      p += len;
  1471.    else
  1472.      p += window->rcol;
  1473.    p = cpb( p );
  1474.  
  1475.    for (c=*p;c != CONTROL_Z && myisalnum( c ); check++) {
  1476.       c = *--p;
  1477.       if (check > 8000) {
  1478.          p = cpb( p );
  1479.          check = 0;
  1480.       }
  1481.    }
  1482.    if (c == CONTROL_Z)
  1483.       return;
  1484.    for (; c != CONTROL_Z && !myisalnum( c ); check++) {
  1485.       c = *--p;
  1486.       if (check > 8000) {
  1487.          p = cpb( p );
  1488.          check = 0;
  1489.       }
  1490.    }
  1491.    if (c == CONTROL_Z)
  1492.       return;
  1493.    for (;c != CONTROL_Z && myisalnum( c ); check++) {
  1494.       c = *--p;
  1495.       if (check > 8000) {
  1496.          p = cpb( p );
  1497.          check = 0;
  1498.       }
  1499.    }
  1500.    find_adjust( window, ++p );
  1501. }
  1502.  
  1503.  
  1504. /*
  1505.  * Name:    word_right
  1506.  * Purpose: To move the cursor one word to the right.
  1507.  * Date:    June 5, 1991
  1508.  * Passed:  window:   information allowing access to the current window
  1509.  * Notes:   Words are considered strings of letters, numbers and underscores,
  1510.  *           which must be separated by other characters.
  1511.  */
  1512. void word_right( window )
  1513. windows *window;
  1514. {
  1515. int len;     /* length of current line */
  1516. text_ptr p;  /* text pointer */
  1517. int c;       /* character at pointer */
  1518. int check = 0;
  1519.  
  1520.    un_copy_line( window->cursor, window, TRUE );
  1521.    p = cpf( window->cursor );
  1522.    len = linelen( p );
  1523.    if (window->rcol > len)
  1524.      p += len;
  1525.    else
  1526.      p += window->rcol;
  1527.    for (c=*p;c != CONTROL_Z && myisalnum( c ); check++) {
  1528.       c = *++p;
  1529.       if (check > 8000) {
  1530.          p = cpf( p );
  1531.          check = 0;
  1532.       }
  1533.    }
  1534.    for (; c != CONTROL_Z && !myisalnum( c ); check++) {
  1535.       c = *++p;
  1536.       if (check > 8000) {
  1537.          p = cpf( p );
  1538.          check = 0;
  1539.       }
  1540.    }
  1541.    if (c != CONTROL_Z)
  1542.       find_adjust( window, p );
  1543. }
  1544.