home *** CD-ROM | disk | FTP | other *** search
/ World of Shareware - Software Farm 2 / wosw_2.zip / wosw_2 / CPROG / TDE31.ZIP / UTILS.C < prev    next >
C/C++ Source or Header  |  1993-08-29  |  80KB  |  2,815 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 1040 characters.
  28.  *
  29.  * In DTE, Doug chose to test whether characters are part of a word.  In TDE,
  30.  * we will test whether characters are not part of a word.  The character
  31.  * set not part of a word will not change as much as the characters that
  32.  * are part of a word.  In most languages, human and computer, the delimiters
  33.  * are much more common across languages than the tokens that make up a word.
  34.  * Thanks to Pierre Jelenc, pcj1@columbia.edu, for recommending looking for
  35.  * delimiters.
  36.  *
  37.  * New editor name:  TDE, the Thomson-Davis Editor.
  38.  * Author:           Frank Davis
  39.  * Date:             June 5, 1991, version 1.0
  40.  * Date:             July 29, 1991, version 1.1
  41.  * Date:             October 5, 1991, version 1.2
  42.  * Date:             January 20, 1992, version 1.3
  43.  * Date:             February 17, 1992, version 1.4
  44.  * Date:             April 1, 1992, version 1.5
  45.  * Date:             June 5, 1992, version 2.0
  46.  * Date:             October 31, 1992, version 2.1
  47.  * Date:             April 1, 1993, version 2.2
  48.  * Date:             June 5, 1993, version 3.0
  49.  * Date:             August 29, 1993, version 3.1
  50.  *
  51.  * This modification of Douglas Thomson's code is released into the
  52.  * public domain, Frank Davis.  You may distribute it freely.
  53.  */
  54.  
  55. #include "tdestr.h"
  56. #include "common.h"
  57. #include "define.h"
  58. #include "tdefunc.h"
  59.  
  60.  
  61. /*
  62.  * Name:    myiswhitespc
  63.  * Purpose: To determine whether or not a character is *NOT* part of a "word".
  64.  * Date:    July 4, 1992
  65.  * Passed:  c: the character to be tested
  66.  * Returns: TRUE if c is in the character set *NOT* part of a word
  67.  * Notes:   The characters in the set not part of a word will not change as
  68.  *           as much as the characters that are part of a word.  In most
  69.  *           languages, human and computer, the delimiters are much more
  70.  *           common than the tokens that make up a word.  For example,
  71.  *           the set of punction characters don't change as much across
  72.  *           languages, human and computer, as the characters that make
  73.  *           up the alphabet, usually.  In other words, the delimiters
  74.  *           are fairly constant across languages.
  75.  */
  76. int  myiswhitespc( int c )
  77. {
  78.    return( c == ' ' || (ispunct( c ) && c != '_') || iscntrl( c ) );
  79. }
  80.  
  81.  
  82. /*
  83.  * Name:    check_virtual_col
  84.  * Purpose: ensure integrity of rcol, ccol, and bcol
  85.  * Date:    June 5, 1991
  86.  * Passed:  window:  pointer to current window
  87.  *          rcol: real column of cursor
  88.  *          ccol: current or logical column of cursor
  89.  */
  90. void check_virtual_col( WINDOW *window, int rcol, int ccol )
  91. {
  92. register int bcol;
  93. int  start_col;
  94. int  end_col;
  95. file_infos *file;
  96.  
  97.    file      = window->file_info;
  98.    bcol      = window->bcol;
  99.    start_col = window->start_col;
  100.    end_col   = window->end_col;
  101.  
  102.    /*
  103.     * is logical column past end of screen?
  104.     */
  105.    if (ccol > end_col) {
  106. /*      ccol = start_col + (end_col + 1 - start_col) / 2;  */
  107.       ccol = end_col;
  108.       bcol = rcol - (ccol - start_col);
  109.       file->dirty = LOCAL;
  110.    }
  111.  
  112.    /*
  113.     * is logical column behind start of screen?
  114.     */
  115.    if (ccol < start_col) {
  116.       if (bcol >= (start_col - ccol))
  117.          bcol -= (start_col - ccol);
  118.       ccol = start_col;
  119.       file->dirty = LOCAL;
  120.    }
  121.  
  122.    /*
  123.     * is real column < base column?
  124.     */
  125.    if (rcol < bcol) {
  126.       ccol = rcol + start_col;
  127.       bcol = 0;
  128.       if (ccol > end_col) {
  129.          bcol = rcol;
  130.          ccol = start_col;
  131.       }
  132.       file->dirty = LOCAL;
  133.    }
  134.  
  135.    /*
  136.     * current column + base column MUST equal real column
  137.     */
  138.    if ((ccol - start_col) + bcol != rcol) {
  139.       if (bcol < 0 || bcol > rcol) {
  140.          bcol = rcol;
  141.          file->dirty = LOCAL;
  142.       }
  143.       ccol = rcol - bcol + start_col;
  144.       if (ccol > end_col) {
  145.          bcol = rcol;
  146.          ccol = start_col;
  147.          file->dirty = LOCAL;
  148.       }
  149.    }
  150.  
  151.    /*
  152.     * rcol CANNOT be negative
  153.     */
  154.    if (rcol < 0) {
  155.       rcol = bcol = 0;
  156.       ccol = start_col;
  157.       file->dirty = LOCAL;
  158.    }
  159.  
  160.    if (rcol >= MAX_LINE_LENGTH) {
  161.       rcol = MAX_LINE_LENGTH - 1;
  162.       bcol = rcol - (ccol - start_col);
  163.    }
  164.  
  165.    assert( rcol >= 0 );
  166.    assert( rcol < MAX_LINE_LENGTH );
  167.    assert( bcol >= 0 );
  168.    assert( bcol < MAX_LINE_LENGTH );
  169.    assert( ccol >= start_col );
  170.    assert( ccol <= end_col );
  171.  
  172.    window->bcol = bcol;
  173.    window->ccol = ccol;
  174.    window->rcol = rcol;
  175. }
  176.  
  177.  
  178. /*
  179.  * Name:    copy_line
  180.  * Purpose: To copy the cursor line, if necessary, into the current line
  181.  *           buffer, so that changes can be made efficiently.
  182.  * Date:    June 5, 1991
  183.  * Passed:  text_line: line to be copied to line buffer
  184.  *          line: line to display error message
  185.  * Notes:   See un_copy_line, the reverse operation.
  186.  *          DO NOT use the C library string functions on text in
  187.  *           g_status.line_buff, because Null characters are allowed as
  188.  *           normal text in the file.
  189.  */
  190. void copy_line( line_list_ptr ll )
  191. {
  192. register unsigned int len;
  193. text_ptr text_line;
  194.  
  195.    if (g_status.copied == FALSE  &&  ll->len != EOF) {
  196.  
  197.       assert( ll != NULL );
  198.  
  199.       len = ll->len;
  200.       text_line = ll->line;
  201.       g_status.buff_node = ll;
  202.  
  203.       assert( len < MAX_LINE_LENGTH );
  204.  
  205.       if (text_line != NULL)
  206.          _fmemcpy( g_status.line_buff, text_line, len );
  207.  
  208.       g_status.line_buff_len = len;
  209.       g_status.copied = TRUE;
  210.    }
  211. }
  212.  
  213.  
  214. /*
  215.  * Name:    un_copy_line
  216.  * Purpose: To copy the cursor line, if necessary, from the current line
  217.  *           buffer, shifting the main text to make the right amount of
  218.  *           room.
  219.  * Date:    June 5, 1991
  220.  * Passed:  test_line:  location in file to copy line buffer
  221.  *          window:  pointer to current window
  222.  *          del_trailing:  delete the trailing blanks at eol? TRUE or FALSE
  223.  * Notes:   For some functions, trailing spaces should not be removed when
  224.  *           returning the line buffer to the main text.  The JoinLine function
  225.  *           is a good example.  We need to leave trailing space so when we
  226.  *           join lines - the current line will extend at least up to
  227.  *           the column of the cursor.  We need to leave trailing space
  228.  *           during BOX block operations.
  229.  *          See copy_line, the reverse operation.
  230.  */
  231. int  un_copy_line( line_list_ptr ll, WINDOW *window, int del_trailing )
  232. {
  233. text_ptr p;
  234. size_t len;     /* length of line buffer text */
  235. size_t ll_len;  /* length of ll->line */
  236. int  net_change;
  237. int  rc;
  238. char c;
  239. file_infos *file;
  240. WINDOW *wp;
  241.  
  242.    rc = OK;
  243.    if (mode.do_backups == TRUE)
  244.       rc = backup_file( window );
  245.  
  246.    if (g_status.copied == TRUE  &&  ll->len != EOF) {
  247.  
  248.       file = window->file_info;
  249.  
  250.       /*
  251.        * if we are deleting the entire line, don't worry about the
  252.        *  deleting the trailing space, since we're deleting entire line.
  253.        */
  254.       if (g_status.command == DeleteLine)
  255.          del_trailing = FALSE;
  256.  
  257.       if (del_trailing  &&  mode.trailing  &&  file->crlf != BINARY) {
  258.          len = g_status.line_buff_len;
  259.          for (p=(text_ptr)(g_status.line_buff+len); len > 0; len--, p--) {
  260.             c = *(p - 1);
  261.             if (c != ' '  &&  c != '\t')
  262.                break;
  263.             if (!mode.inflate_tabs && c == '\t')
  264.                break;
  265.          }
  266.          g_status.line_buff_len = len;
  267.          file->dirty = GLOBAL;
  268.          if (window->visible == TRUE)
  269.             show_changed_line( window );
  270.       }
  271.       len = g_status.line_buff_len;
  272.       ll_len =  (ll->line == NULL) ? 0 : ll->len;
  273.  
  274.  
  275.       assert( len < MAX_LINE_LENGTH );
  276.       assert( ll_len < MAX_LINE_LENGTH );
  277.  
  278.       net_change = len - ll_len;
  279.  
  280.       if (ll_len != len  ||  ll->line == NULL) {
  281.          /*
  282.           * let malloc space for the new line before we free the old line.
  283.           */
  284.          p = my_malloc( len, &rc );
  285.          if (rc == ERROR)
  286.             error( WARNING, window->bottom_line, main4 );
  287.  
  288.          /*
  289.           * free the space taken up by current line in far heap.
  290.           */
  291.          if (rc != ERROR  &&  ll->line != NULL)
  292.             my_free( ll->line );
  293.       } else
  294.          p = ll->line;
  295.  
  296.       if (rc != ERROR) {
  297.          if (len > 0)
  298.             _fmemcpy( p, g_status.line_buff, len );
  299.          ll->line = p;
  300.          ll->len = len;
  301.  
  302.          if (net_change != 0) {
  303.             for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  304.                if (wp->file_info == file && wp != window)
  305.                   if (wp->rline > window->rline)
  306.                      wp->bin_offset += net_change;
  307.             }
  308.          }
  309.  
  310.          file->modified = TRUE;
  311.          show_avail_mem( );
  312.       }
  313.    }
  314.    g_status.copied = FALSE;
  315.    return( rc );
  316. }
  317.  
  318.  
  319. /*
  320.  * Name:    un_copy_tab_buffer
  321.  * Purpose: To copy the tab buffer line the main text buffer
  322.  * Date:    October 31, 1992
  323.  * Passed:  line_number:  line number to copy line tab out buffer
  324.  *          window:       pointer to current window
  325.  */
  326. int  un_copy_tab_buffer( line_list_ptr ll, WINDOW *window )
  327. {
  328. text_ptr p;
  329. int  len;               /* length of current line buffer text */
  330. int  net_change;
  331. int  rc;
  332. file_infos *file;
  333. WINDOW *wp;
  334.  
  335.    rc = OK;
  336.    file = window->file_info;
  337.    /*
  338.     * file has changed.  lets create the back_up if needed
  339.     */
  340.    if (mode.do_backups == TRUE) {
  341.       window->file_info->modified = TRUE;
  342.       rc = backup_file( window );
  343.    }
  344.  
  345.    len = g_status.tabout_buff_len;
  346.  
  347.    assert( len >= 0 );
  348.    assert( len < MAX_LINE_LENGTH );
  349.    assert( ll->len >= 0 );
  350.    assert( ll->len < MAX_LINE_LENGTH );
  351.  
  352.    /*
  353.     * if the far heap has run out of space, then only part of the
  354.     *  current line can be moved back into the far heap. Warn the user
  355.     *  that some of the current line has been lost.
  356.     */
  357.    p = my_malloc( len, &rc );
  358.    if (rc == ERROR)
  359.       error( WARNING, window->bottom_line, main4 );
  360.  
  361.    if (rc == OK) {
  362.       net_change = len - ll->len;
  363.  
  364.       if (ll->line != NULL)
  365.          my_free( ll->line );
  366.       if (len > 0)
  367.          _fmemcpy( p, g_status.line_buff, len );
  368.       ll->line = p;
  369.       ll->len  = len;
  370.  
  371.       if (net_change != 0) {
  372.          for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  373.             if (wp->file_info == file && wp != window)
  374.                if (wp->rline > window->rline)
  375.                   wp->bin_offset += net_change;
  376.          }
  377.       }
  378.  
  379.       file->modified = TRUE;
  380.    }
  381.    return( rc );
  382. }
  383.  
  384.  
  385. /*
  386.  * Name:    load_undo_buffer
  387.  * Purpose: To copy the cursor line to the undo buffer.
  388.  * Date:    September 26, 1991
  389.  * Passed:  file:          pointer to file
  390.  *          line_to_undo:  pointer to line in file to save
  391.  * Notes:   save the last mode.undo_max lines in a stack.  when we overflow
  392.  *           the stack, dump the oldest line.
  393.  */
  394. void load_undo_buffer( file_infos *file, text_ptr line_to_undo, int len )
  395. {
  396. int  rc;
  397. text_ptr l;
  398. line_list_ptr temp_ll;
  399.  
  400.    rc = OK;
  401.    if (file->undo_count >= mode.undo_max) {
  402.       --file->undo_count;
  403.       temp_ll = file->undo_bot->prev;
  404.       temp_ll->prev->next = file->undo_bot;
  405.       file->undo_bot->prev = temp_ll->prev;
  406.       if (temp_ll->line != NULL)
  407.          my_free( temp_ll->line );
  408.    } else
  409.       temp_ll = (line_list_ptr)my_malloc( sizeof(line_list_struc), &rc );
  410.  
  411.    assert( len >= 0 );
  412.    assert( len < MAX_LINE_LENGTH );
  413.  
  414.    l = my_malloc( len, &rc );
  415.  
  416.    if (rc == ERROR) {
  417.       if (l != NULL)
  418.          my_free( l );
  419.       if (temp_ll != NULL)
  420.          my_free( temp_ll );
  421.    } else {
  422.       if (len > 0)
  423.          _fmemcpy( l, line_to_undo, len );
  424.       temp_ll->line  = l;
  425.       temp_ll->len   = len;
  426.       temp_ll->dirty = TRUE;
  427.  
  428.       temp_ll->prev = NULL;
  429.       temp_ll->next = file->undo_top;
  430.       file->undo_top->prev = temp_ll;
  431.       file->undo_top = temp_ll;
  432.  
  433.       ++file->undo_count;
  434.    }
  435. }
  436.  
  437.  
  438. /*
  439.  * Name:    set_prompt
  440.  * Purpose: To display a prompt, highlighted, at the bottom of the screen.
  441.  * Date:    October 1, 1989
  442.  * Passed:  prompt: prompt to be displayed
  443.  *          line:   line to display prompt
  444.  */
  445. void set_prompt( char *prompt, int line )
  446. {
  447. register int prompt_col;
  448.  
  449.    /*
  450.     * work out where the answer should go
  451.     */
  452.    prompt_col = strlen( prompt );
  453.  
  454.    assert( prompt_col <= MAX_COLS );
  455.  
  456.    /*
  457.     * output the prompt
  458.     */
  459.    s_output( prompt, line, 0, g_display.message_color );
  460.    eol_clear( prompt_col, line, g_display.message_color );
  461.  
  462.    /*
  463.     * put cursor at end of prompt
  464.     */
  465.    xygoto( prompt_col, line );
  466. }
  467.  
  468.  
  469. /*
  470.  * Name:    get_name
  471.  * Purpose: To prompt the user and read the string entered in response.
  472.  * Date:    June 5, 1992
  473.  * Passed:  prompt: prompt to offer the user
  474.  *          line:   line to display prompt
  475.  *          name:   default answer
  476.  *          color:  color to display prompt
  477.  * Returns: name:   user's answer
  478.  *          OK if user entered something
  479.  *          ERROR if user aborted the command
  480.  * Notes:   with the addition of macros in tde, this function became a little
  481.  *           more complicated.  we have to deal with both executing macros
  482.  *           and macros that are the user uses when entering normal text
  483.  *           at the prompt.  i call these local and global macros.  a global
  484.  *           macro is when this function is called from a running macro.
  485.  *           the running macro can enter text and return from this function
  486.  *           w/o any action from the user.  a local macro is when the user
  487.  *           presses a key inside this function, which happens quite often
  488.  *           when keys are assigned to ASCII and Extended ASCII characters.
  489.  */
  490. int  get_name( char *prompt, int line, char *name, int color )
  491. {
  492. int  col;               /* cursor column for answer */
  493. int  c;                 /* character user just typed */
  494. char *cp;               /* cursor position in answer */
  495. char *answer;           /* user's answer */
  496. int first = TRUE;       /* first character typed */
  497. register int len;       /* length of answer */
  498. int  plen;              /* length of prompt */
  499. int  func;              /* function of key pressed */
  500. int  stop;              /* flag to stop getting characters */
  501. char *p;                /* for copying text in answer */
  502. char buffer[MAX_COLS+2];/* line on which name is being entered */
  503. char line_buff[(MAX_COLS+1)*2]; /* buffer for char and attribute  */
  504. int  normal;
  505. int  local_macro = FALSE;
  506. int  next;
  507. int  regx_help_on;
  508. char **pp;
  509. int  i;
  510.  
  511.    /*
  512.     * set up prompt and default
  513.     */
  514.    assert( strlen( prompt ) < MAX_COLS );
  515.    assert( strlen( name )   < MAX_COLS );
  516.  
  517.    strcpy( buffer, prompt );
  518.    plen = strlen( prompt );
  519.    answer = buffer + plen;
  520.    strcpy( answer, name );
  521.  
  522.    /*
  523.     * let user edit default string
  524.     */
  525.    regx_help_on = FALSE;
  526.    len = strlen( answer );
  527.    col = strlen( buffer );
  528.    g_status.prompt_line = line;
  529.    g_status.prompt_col = col;
  530.    cp = answer + len;
  531.    normal = g_display.text_color;
  532.    save_screen_line( 0, line, line_buff );
  533.    s_output( buffer, line, 0, color );
  534.    eol_clear( col, line, normal );
  535.    for (stop = FALSE; stop == FALSE;) {
  536.       if (regx_help_on == TRUE)
  537.          xygoto( -1, -1 );
  538.       else
  539.          xygoto( col, line );
  540.       if (g_status.macro_executing) {
  541.          next = g_status.macro_next;
  542.          g_status.macro_next = macro.strokes[g_status.macro_next].next;
  543.          if (g_status.macro_next != -1) {
  544.             c = macro.strokes[g_status.macro_next].key;
  545.             func = getfunc( c );
  546.             if (func == PlayBack) {
  547.                stop = TRUE;
  548.                g_status.macro_next = next;
  549.             }
  550.          } else {
  551.             c = 0x100;
  552.             func = AbortCommand;
  553.             stop = TRUE;
  554.          }
  555.       } else {
  556.          if (local_macro == FALSE) {
  557.             c = getkey( );
  558.             func = getfunc( c );
  559.  
  560.             /*
  561.              * User may have redefined the Enter and ESC keys.  Make the Enter
  562.              *  key perform a Rturn in this function. Make the ESC key do an
  563.              *  AbortCommand.
  564.              */
  565.             if (c == RTURN)
  566.                func = Rturn;
  567.             else if (c == ESC)
  568.                func = AbortCommand;
  569.  
  570.             if (func == PlayBack) {
  571.                local_macro = TRUE;
  572.                next = macro.first_stroke[ c-256 ];
  573.                c = macro.strokes[next].key;
  574.                func = getfunc( c );
  575.                next = macro.strokes[next].next;
  576.             } else {
  577.                g_status.key_pressed = c;
  578.                record_keys( line );
  579.             }
  580.          } else {
  581.             if (next != -1) {
  582.                c = macro.strokes[next].key;
  583.                next = macro.strokes[next].next;
  584.             } else {
  585.                local_macro = FALSE;
  586.                c = 0x100;
  587.             }
  588.             func = getfunc( c );
  589.          }
  590.       }
  591.       if (c == _F1)
  592.          func = Help;
  593.       if (regx_help_on == TRUE  &&  g_status.current_window != NULL) {
  594.          redraw_screen( g_status.current_window );
  595.          s_output( buffer, line, 0, color );
  596.          eol_clear( col, line, normal );
  597.          s_output( cp, line, col, color );
  598.          regx_help_on = FALSE;
  599.       } else {
  600.          switch (func) {
  601.             case Help :
  602.                if ((g_status.command == FindRegX  ||
  603.                     g_status.command == RepeatFindRegX) &&
  604.                     regx_help_on == FALSE) {
  605.                   regx_help_on = TRUE;
  606.                   for (i=3,pp=regx_help; *pp != NULL; pp++, i++)
  607.                      s_output( *pp, i, 12, g_display.help_color );
  608.                }
  609.                break;
  610.             case ToggleSearchCase :
  611.                mode.search_case = mode.search_case == IGNORE ? MATCH : IGNORE;
  612.                build_boyer_array( );
  613.                show_search_case( );
  614.                break;
  615.             case Rturn       :
  616.             case NextLine    :
  617.             case BegNextLine :
  618.                answer[len] = '\0';
  619.                assert( strlen( answer ) < MAX_COLS );
  620.                strcpy( name, answer );
  621.                /*
  622.                 * finished
  623.                 */
  624.                stop = TRUE;
  625.                break;
  626.             case BackSpace :
  627.                /*
  628.                 * delete to left of cursor
  629.                 */
  630.                if (cp > answer) {
  631.                   for (p=cp-1; p < answer+len; p++) {
  632.                      *p = *(p+1);
  633.                   }
  634.                   --len;
  635.                   --col;
  636.                   --cp;
  637.                   c_output( ' ', plen+len, line, normal );
  638.                   s_output( cp, line, col, color );
  639.                   *(answer + len) = '\0';
  640.                }
  641.                break;
  642.             case DeleteChar :
  643.                /*
  644.                 * delete char under cursor
  645.                 */
  646.                if (*cp) {
  647.                   for (p=cp; p < answer+len; p++) {
  648.                      *p = *(p+1);
  649.                   }
  650.                   --len;
  651.                   c_output( ' ', plen+len, line, normal );
  652.                   s_output( cp, line, col, color );
  653.                   *(answer + len) = '\0';
  654.                }
  655.                break;
  656.             case DeleteLine :
  657.                /*
  658.                 * delete current line
  659.                 */
  660.                col = plen;
  661.                cp = answer;
  662.                *cp = '\0';
  663.                len = 0;
  664.                eol_clear( col, line, normal );
  665.                break;
  666.             case AbortCommand :
  667.                stop = TRUE;
  668.                break;
  669.             case CharLeft :
  670.                /*
  671.                 * move cursor left
  672.                 */
  673.                if (cp > answer) {
  674.                   col--;
  675.                   cp--;
  676.                }
  677.                break;
  678.             case CharRight :
  679.                /*
  680.                 * move cursor right
  681.                 */
  682.                if (*cp) {
  683.                   col++;
  684.                   cp++;
  685.                 }
  686.                 break;
  687.             case BegOfLine :
  688.                /*
  689.                 * move cursor to start of line
  690.                 */
  691.                col = plen;
  692.                cp = answer;
  693.                break;
  694.             case EndOfLine :
  695.                /*
  696.                 * move cursor to end of line
  697.                 */
  698.                col = plen + len;
  699.                cp = answer + len;
  700.                break;
  701.             default :
  702.                if (c < 0x100) {
  703.                   /*
  704.                    * insert character at cursor
  705.                    */
  706.                   if (first) {
  707.                      /*
  708.                       * delete previous answer
  709.                       */
  710.                      col = plen;
  711.                      cp = answer;
  712.                      *cp = '\0';
  713.                      len = 0;
  714.                      eol_clear( col, line, normal );
  715.                   }
  716.  
  717.                   /*
  718.                    * insert new character
  719.                    */
  720.                   if (col < g_display.ncols-1) {
  721.                      if (*cp == '\0') {
  722.                         ++len;
  723.                         *(answer + len) = '\0';
  724.                      }
  725.                      *cp = (char)c;
  726.                      c_output( c, col, line, color );
  727.                      ++cp;
  728.                      ++col;
  729.                   }
  730.                }
  731.                break;
  732.          }
  733.       }
  734.       first = FALSE;
  735.    }
  736.    restore_screen_line( 0, line, line_buff );
  737.    return( func == AbortCommand ? ERROR : OK );
  738. }
  739.  
  740.  
  741. /*
  742.  * Name:    get_sort_order
  743.  * Purpose: To prompt the user and get sort direction
  744.  * Date:    June 5, 1992
  745.  * Passed:  window
  746.  * Returns: OK if user entered something
  747.  *          ERROR if user aborted the command
  748.  */
  749. int  get_sort_order( WINDOW *window )
  750. {
  751. register int c;
  752. int  col;
  753. char line_buff[(MAX_COLS+1)*2];         /* buffer for char and attribute  */
  754.  
  755.    save_screen_line( 0, window->bottom_line, line_buff );
  756.    /*
  757.     * sort ascending or descending
  758.     */
  759.    s_output( utils4, window->bottom_line, 0, g_display.message_color );
  760.    c = strlen( utils4 );
  761.    eol_clear( c, window->bottom_line, g_display.text_color );
  762.    xygoto( c, window->bottom_line );
  763.    do {
  764.       c = getkey( );
  765.       col = getfunc( c );
  766.       if (c == ESC)
  767.          col = AbortCommand;
  768.    } while (col != AbortCommand  &&  c != 'A'  &&  c != 'a'  &&
  769.             c != 'D'  &&  c != 'd');
  770.    switch ( c ) {
  771.       case 'A' :
  772.       case 'a' :
  773.          sort.direction = ASCENDING;
  774.          break;
  775.       case 'D' :
  776.       case 'd' :
  777.          sort.direction = DESCENDING;
  778.          break;
  779.       default  :
  780.          col = AbortCommand;
  781.          break;
  782.    }
  783.    restore_screen_line( 0, window->bottom_line, line_buff );
  784.    return( col == AbortCommand ? ERROR : OK );
  785. }
  786.  
  787.  
  788. /*
  789.  * Name:    get_replace_direction
  790.  * Purpose: To prompt the user and get replace string direction
  791.  * Date:    October 31, 1992
  792.  * Passed:  window
  793.  * Returns: OK if user entered something
  794.  *          ERROR if user aborted the command
  795.  */
  796. int  get_replace_direction( WINDOW *window )
  797. {
  798. register int c;
  799. int  col;
  800. char line_buff[(MAX_COLS+1)*2];         /* buffer for char and attribute  */
  801.  
  802.    save_screen_line( 0, window->bottom_line, line_buff );
  803.    /*
  804.     * replace forward or backward
  805.     */
  806.    s_output( utils5, window->bottom_line, 0, g_display.message_color );
  807.    c = strlen( utils5 );
  808.    eol_clear( c, window->bottom_line, g_display.text_color );
  809.    xygoto( c, window->bottom_line );
  810.    do {
  811.       c = getkey( );
  812.       col = getfunc( c );
  813.       if (c == ESC)
  814.          col = AbortCommand;
  815.    } while (col != AbortCommand  &&  c != 'F'  &&  c != 'f'  &&
  816.             c != 'B'  &&  c != 'b');
  817.    switch ( c ) {
  818.       case 'F' :
  819.       case 'f' :
  820.          c = FORWARD;
  821.          break;
  822.       case 'B' :
  823.       case 'b' :
  824.          c = BACKWARD;
  825.          break;
  826.       default  :
  827.          c = ERROR;
  828.    }
  829.    restore_screen_line( 0, window->bottom_line, line_buff );
  830.    return( col == AbortCommand ? ERROR : c );
  831. }
  832.  
  833.  
  834. /*
  835.  * Name:    get_yn
  836.  * Purpose: To input a response of yes or no.
  837.  * Date:    October 1, 1989
  838.  * Returns: the user's answer.  A_??? - see tdestr.h
  839.  */
  840. int  get_yn( void )
  841. {
  842. int  c;                 /* the user's response */
  843. register int rc;        /* return code */
  844.  
  845.    do {
  846.       c = getkey( );
  847.       rc = getfunc( c );
  848.       if (c== ESC)
  849.          rc = AbortCommand;
  850.    } while (rc != AbortCommand  &&  c != 'Y'  &&  c != 'y'  &&
  851.             c != 'N'  &&  c != 'n');
  852.    if (rc == AbortCommand || c == ESC)
  853.       rc = ERROR;
  854.    else {
  855.       switch ( c ) {
  856.          case 'Y' :
  857.          case 'y' :
  858.             rc = A_YES;
  859.             break;
  860.          case 'N' :
  861.          case 'n' :
  862.             rc = A_NO;
  863.             break;
  864.       }
  865.    }
  866.    return( rc );
  867. }
  868.  
  869.  
  870. /*
  871.  * Name:    get_lr
  872.  * Purpose: To input a response of yes or no.
  873.  * Date:    June 1, 1991
  874.  * Returns: the user's answer, LEFT or RIGHT.
  875.  */
  876. int  get_lr( void )
  877. {
  878. int  c;                 /* the user's response */
  879. register int rc;        /* return code */
  880.  
  881.    for (rc=OK; rc == OK;) {
  882.       c = getkey( );
  883.       if (getfunc( c ) == AbortCommand || c == ESC)
  884.          rc = ERROR;
  885.       else {
  886.          switch ( c ) {
  887.             case 'L' :
  888.             case 'l' :
  889.                rc = LEFT;
  890.                break;
  891.             case 'R' :
  892.             case 'r' :
  893.                rc = RIGHT;
  894.                break;
  895.          }
  896.       }
  897.    }
  898.    return( rc );
  899. }
  900.  
  901.  
  902. /*
  903.  * Name:    get_bc
  904.  * Purpose: To input a response of beginning or current cursor postion
  905.  * Date:    October 31, 1992
  906.  * Returns: the user's answer, Beginning or Current.
  907.  */
  908. int  get_bc( void )
  909. {
  910. int  c;                 /* the user's response */
  911. register int rc;        /* return code */
  912.  
  913.    for (rc=OK; rc == OK;) {
  914.       c = getkey( );
  915.       if (getfunc( c ) == AbortCommand || c == ESC)
  916.          rc = ERROR;
  917.       else {
  918.          switch ( c ) {
  919.             case 'B' :
  920.             case 'b' :
  921.                rc = BEGINNING;
  922.                break;
  923.             case 'C' :
  924.             case 'c' :
  925.                rc = CURRENT;
  926.                break;
  927.          }
  928.       }
  929.    }
  930.    return( rc );
  931. }
  932.  
  933.  
  934. /*
  935.  * Name:    get_oa
  936.  * Purpose: To input a response of overwrite or append.
  937.  * Date:    October 1, 1989
  938.  * Returns: the user's answer.  A_??? - see tdestr.h
  939.  */
  940. int  get_oa( void )
  941. {
  942. int  c;                 /* the user's response */
  943. register int rc;        /* return code */
  944. int  func;
  945.  
  946.    rc = 0;
  947.    while (rc != AbortCommand && rc != A_OVERWRITE && rc != A_APPEND) {
  948.       c = getkey( );
  949.       func = getfunc( c );
  950.       if (func == AbortCommand || c == ESC)
  951.          rc = AbortCommand;
  952.       switch ( c ) {
  953.          case 'O' :
  954.          case 'o' :
  955.             rc = A_OVERWRITE;
  956.             break;
  957.          case 'A' :
  958.          case 'a' :
  959.             rc = A_APPEND;
  960.             break;
  961.       }
  962.    }
  963.    return( rc );
  964. }
  965.  
  966.  
  967. /*
  968.  * Name:    show_eof
  969.  * Purpose: display eof message
  970.  * Date:    September 16, 1991
  971.  * Notes:   line:  ususally, line to is display "<=== eof ===>"
  972.  */
  973. void show_eof( WINDOW *window )
  974. {
  975. register int color;
  976. char temp[MAX_COLS+2];
  977.  
  978.    assert( strlen( mode.eof ) < MAX_COLS );
  979.  
  980.    strcpy( temp, mode.eof );
  981.    color = window->end_col + 1 - window->start_col;
  982.    if (strlen( temp ) > (unsigned)color)
  983.       temp[color] = '\0';
  984.    color = g_display.eof_color;
  985.    window_eol_clear( window, color );
  986.    s_output( temp, window->cline, window->start_col, color );
  987. }
  988.  
  989.  
  990. /*
  991.  * Name:    display_current_window
  992.  * Purpose: display text in current window
  993.  * Date:    June 5, 1991
  994.  * Passed:  window:  pointer to current window
  995.  * Notes:   use a temporary window structure, "w", to do the dirty work.
  996.  */
  997. void display_current_window( WINDOW *window )
  998. {
  999. int  count;     /* number of lines updated so far */
  1000. int  number;    /* number of lines visible in window */
  1001. register int i; /* register variable */
  1002. WINDOW w;       /* scratch window structure */
  1003. int  curl;      /* current line on screen, window->cline */
  1004. int  eof;
  1005.  
  1006.    /*
  1007.     * initialize the scratch variables
  1008.     */
  1009.    number = window->bottom_line - ((window->top_line + window->ruler) - 1);
  1010.    count  = window->cline - (window->top_line + window->ruler);
  1011.    dup_window_info( &w, window );
  1012.  
  1013.    w.cline -= count;
  1014.    w.rline -= count;
  1015.    for (eof=count; eof > 0; eof--)
  1016.       w.ll = w.ll->prev;
  1017.  
  1018.  
  1019.    /*
  1020.     * start at the top of the window and display a window full of text
  1021.     */
  1022.    eof = FALSE;
  1023.    curl = window->cline;
  1024.    for (i=number; i>0; i--) {
  1025.       if (w.ll->len != EOF) {
  1026.          /*
  1027.           * if this is window->cline, do not show the line because we
  1028.           *  show the curl at the end of this function.  don't show it twice
  1029.           */
  1030.          if (w.cline != curl)
  1031.             update_line( &w );
  1032.          w.ll = w.ll->next;
  1033.       } else if (eof == FALSE) {
  1034.          show_eof( &w );
  1035.          eof = TRUE;
  1036.       } else
  1037.          window_eol_clear( &w, COLOR_TEXT );
  1038.       ++w.cline;
  1039.       ++w.rline;
  1040.    }
  1041.    show_asterisk( window );
  1042.    show_curl_line( window );
  1043. }
  1044.  
  1045.  
  1046. /*
  1047.  * Name:    redraw_screen
  1048.  * Purpose: display all visible windows, modes, and headers
  1049.  * Date:    June 5, 1991
  1050.  * Passed:  window:  pointer to current window
  1051.  */
  1052. int  redraw_screen( WINDOW *window )
  1053. {
  1054. register WINDOW *above;        /* window above current */
  1055. register WINDOW *below;        /* window below current */
  1056.  
  1057.    cls( );
  1058.    /*
  1059.     * display the current window
  1060.     */
  1061.    redraw_current_window( window );
  1062.  
  1063.    /*
  1064.     * now update all the other windows
  1065.     */
  1066.    above = below = window;
  1067.    while (above->prev || below->next) {
  1068.       if (above->prev) {
  1069.          above = above->prev;
  1070.          redraw_current_window( above );
  1071.       }
  1072.       if (below->next) {
  1073.          below = below->next;
  1074.          redraw_current_window( below );
  1075.       }
  1076.    }
  1077.    window->file_info->dirty = FALSE;
  1078.    show_modes( );
  1079.    return( OK );
  1080. }
  1081.  
  1082.  
  1083. /*
  1084.  * Name:    redraw_current_window
  1085.  * Purpose: redraw all info in window
  1086.  * Date:    July 13, 1991
  1087.  * Passed:  window:  pointer to current window
  1088.  */
  1089. void redraw_current_window( WINDOW *window )
  1090. {
  1091.  
  1092.    /*
  1093.     * display the current window
  1094.     */
  1095.    if (window->visible) {
  1096.       display_current_window( window );
  1097.       show_window_header( window );
  1098.       show_ruler( window );
  1099.       show_ruler_pointer( window );
  1100.       if (window->vertical)
  1101.          show_vertical_separator( window );
  1102.    }
  1103. }
  1104.  
  1105.  
  1106. /*
  1107.  * Name:    show_changed_line
  1108.  * Purpose: Only one line was changed in file, just show it
  1109.  * Date:    June 5, 1991
  1110.  * Passed:  window:  pointer to current window
  1111.  */
  1112. void show_changed_line( WINDOW *window )
  1113. {
  1114. WINDOW *above;                  /* window above current */
  1115. WINDOW *below;                  /* window below current */
  1116. WINDOW w;                       /* scratch window structure */
  1117. long changed_line;              /* line number in file that was changed */
  1118. long top_line, bottom_line;     /* top and bottom line in file on screen */
  1119. int  line_on_screen;            /* is changed line on screen? */
  1120. file_infos *file;               /* file pointer */
  1121.  
  1122.    file = window->file_info;
  1123.    if ((file->dirty == LOCAL || file->dirty == GLOBAL) && window->visible)
  1124.       show_curl_line( window );
  1125.    changed_line = window->rline;
  1126.  
  1127.    /*
  1128.     * now update the line in all other windows
  1129.     */
  1130.    if (file->dirty != LOCAL) {
  1131.       above = below = window;
  1132.       while (above->prev || below->next) {
  1133.          if (above->prev) {
  1134.             above = above->prev;
  1135.             dup_window_info( &w, above );
  1136.          } else if (below->next) {
  1137.             below = below->next;
  1138.             dup_window_info( &w, below );
  1139.          }
  1140.  
  1141.          /*
  1142.           * is this window the changed file and is it visible?
  1143.           */
  1144.          if (w.file_info == file && w.visible) {
  1145.  
  1146.             /*
  1147.              * calculate file lines at top and bottom of screen.
  1148.              * the changed line may not be the curl in other windows.
  1149.              */
  1150.             line_on_screen = FALSE;
  1151.             top_line = w.rline - (w.cline - (w.top_line + w.ruler));
  1152.             bottom_line = w.rline + (w.bottom_line - w.cline);
  1153.             if (changed_line == w.rline)
  1154.                line_on_screen = CURLINE;
  1155.             else if (changed_line < w.rline && changed_line >= top_line) {
  1156.                line_on_screen = NOTCURLINE;
  1157.                while (w.rline > changed_line) {
  1158.                   w.ll = w.ll->prev;
  1159.                   --w.rline;
  1160.                   --w.cline;
  1161.                }
  1162.             } else if (changed_line > w.rline && changed_line <= bottom_line) {
  1163.                line_on_screen = NOTCURLINE;
  1164.                while (w.rline < changed_line) {
  1165.                   w.ll = w.ll->next;
  1166.                   ++w.rline;
  1167.                   ++w.cline;
  1168.                }
  1169.             }
  1170.  
  1171.             /*
  1172.              * display the changed line if on screen
  1173.              */
  1174.             if (line_on_screen == NOTCURLINE)
  1175.                update_line( &w );
  1176.             else if (line_on_screen == CURLINE)
  1177.                show_curl_line( &w );
  1178.          }
  1179.       }
  1180.    }
  1181.    file->dirty = FALSE;
  1182. }
  1183.  
  1184.  
  1185. /*
  1186.  * Name:    show_curl_line
  1187.  * Purpose: show current line in curl color
  1188.  * Date:    January 16, 1992
  1189.  * Passed:  window:  pointer to current window
  1190.  */
  1191. void show_curl_line( WINDOW *window )
  1192. {
  1193. int  text_color;
  1194. int  dirty_color;
  1195.  
  1196.    if (window->visible  &&  g_status.screen_display) {
  1197.       text_color = g_display.text_color;
  1198.       dirty_color = g_display.dirty_color;
  1199.       g_display.dirty_color = g_display.text_color = g_display.curl_color;
  1200.       update_line( window );
  1201.       g_display.text_color = text_color;
  1202.       g_display.dirty_color = dirty_color;
  1203.    }
  1204. }
  1205.  
  1206.  
  1207. /*
  1208.  * Name:    dup_window_info
  1209.  * Purpose: Copy window info from one window pointer to another
  1210.  * Date:    June 5, 1991
  1211.  * Passed:  dw: destination window
  1212.  *          sw: source window
  1213.  */
  1214. void dup_window_info( WINDOW *dw, WINDOW *sw )
  1215. {
  1216.    memcpy( dw, sw, sizeof( WINDOW ) );
  1217. }
  1218.  
  1219.  
  1220. /*
  1221.  * Name:    adjust_windows_cursor
  1222.  * Purpose: A change has been made, make sure pointers are not ahead of
  1223.  *           or behind file.
  1224.  * Date:    June 5, 1991
  1225.  * Passed:  window:       pointer to current window
  1226.  *          line_change:  number of lines add to or subtracted from file
  1227.  * Notes:   If a file has been truncated in one window and there is another
  1228.  *           window open to the same file and its current line is near the
  1229.  *           end, the current line is reset to the last line of the file.
  1230.  */
  1231. void adjust_windows_cursor( WINDOW *window, long line_change )
  1232. {
  1233. register WINDOW *next;
  1234. long i;
  1235. file_infos *file;
  1236. MARKER *marker;
  1237. long length;
  1238.  
  1239.    file = window->file_info;
  1240.    length = file->length;
  1241.    next = g_status.window_list;
  1242.    while (next != NULL) {
  1243.       if (next != window) {
  1244.          if (next->file_info == file) {
  1245.             if (next->rline > length + 1) {
  1246.                next->rline = length;
  1247.                next->ll    = file->line_list_end;
  1248.                file->dirty = NOT_LOCAL;
  1249.             } else if (next->rline < 1) {
  1250.                next->rline = 1;
  1251.                next->cline = next->top_line + next->ruler;
  1252.                next->ll    = file->line_list;
  1253.                next->bin_offset = 0;
  1254.                file->dirty = NOT_LOCAL;
  1255.             }
  1256.             if (next->rline > window->rline  &&  line_change) {
  1257.                file->dirty = NOT_LOCAL;
  1258.                if (line_change < 0) {
  1259.                   for (i=line_change; i < 0 && next->ll->next != NULL; i++) {
  1260.                      next->bin_offset += next->ll->len;
  1261.                      next->ll = next->ll->next;
  1262.                   }
  1263.                } else if (line_change > 0) {
  1264.                   for (i=line_change; i > 0 && next->ll->prev != NULL; i--) {
  1265.                      next->ll = next->ll->prev;
  1266.                      next->bin_offset -= next->ll->len;
  1267.                   }
  1268.                }
  1269.             }
  1270.             if (next->rline < (next->cline -(next->top_line+next->ruler-1))) {
  1271.                next->cline = (int)next->rline+(next->top_line+next->ruler)-1;
  1272.                file->dirty = NOT_LOCAL;
  1273.             }
  1274.          }
  1275.       }
  1276.       next = next->next;
  1277.    }
  1278.  
  1279.    /*
  1280.     * now adjust any markers.
  1281.     */
  1282.    for (i=0; i<3; i++) {
  1283.       marker = &file->marker[ (int) i ];
  1284.       if (marker->rline > window->rline) {
  1285.          marker->rline += line_change;
  1286.          if (marker->rline < 1L)
  1287.             marker->rline = 1L;
  1288.          else if (marker->rline > length)
  1289.             marker->rline = length;
  1290.       }
  1291.    }
  1292. }
  1293.  
  1294.  
  1295. /*
  1296.  * Name:    first_non_blank
  1297.  * Purpose: To find the column of the first non-blank character
  1298.  * Date:    June 5, 1991
  1299.  * Passed:  s:    the string to search
  1300.  *          len:  length of string
  1301.  * Returns: the first non-blank column
  1302.  */
  1303. int  first_non_blank( text_ptr s, int len )
  1304. {
  1305. register int count = 0;
  1306.  
  1307.    if (s != NULL) {
  1308.       if (mode.inflate_tabs) {
  1309.          for (; len > 0 && (*s == ' ' || *s == '\t'); s++, len--) {
  1310.             if (*s != '\t')
  1311.                ++count;
  1312.             else
  1313.                count += mode.ptab_size - (count % mode.ptab_size);
  1314.          }
  1315.       } else {
  1316.          while (len-- > 0  &&  *s++ == ' ')
  1317.            ++count;
  1318.       }
  1319.    }
  1320.    return( count );
  1321. }
  1322.  
  1323.  
  1324. /*
  1325.  * Name:    find_end
  1326.  * Purpose: To find the last character in a line
  1327.  * Date:    October 31, 1992
  1328.  * Passed:  s:    the string to search
  1329.  *          len:  length of string
  1330.  * Returns: the first non-blank column
  1331.  */
  1332. int  find_end( text_ptr s, int len )
  1333. {
  1334. register int count = 0;
  1335.  
  1336.    if (s != NULL) {
  1337.       if (mode.inflate_tabs) {
  1338.          for (;len > 0; s++, len--) {
  1339.             if (*s == '\t')
  1340.                count += mode.ptab_size - (count % mode.ptab_size);
  1341.             else
  1342.                ++count;
  1343.          }
  1344.       } else
  1345.          count = len;
  1346.    }
  1347.    return( count );
  1348. }
  1349.  
  1350.  
  1351. /*
  1352.  * Name:    is_line_blank
  1353.  * Purpose: is line empty or does it only contain spaces?
  1354.  * Date:    November 28, 1991
  1355.  * Passed:  s:    the string to search
  1356.  *          len:  length of string
  1357.  * Returns: TRUE if line is blank or FALSE if something is in line
  1358.  */
  1359. int is_line_blank( text_ptr s, int len )
  1360. {
  1361.    if (s != NULL) {
  1362.       if (mode.inflate_tabs) {
  1363.         while (len > 0  &&  (*s == ' ' || *s == '\t')) {
  1364.            ++s;
  1365.            --len;
  1366.         }
  1367.       } else {
  1368.          while (len > 0  &&  *s == ' ') {
  1369.             ++s;
  1370.             --len;
  1371.          }
  1372.       }
  1373.    } else
  1374.       len = 0;
  1375.    return( len == 0 );
  1376. }
  1377.  
  1378.  
  1379. /*
  1380.  * Name:    page_up
  1381.  * Purpose: To move the cursor one page up the window
  1382.  * Date:    June 5, 1991
  1383.  * Passed:  window:  pointer to current window
  1384.  * Notes:   The cursor line is moved back the required number of lines
  1385.  *           towards the start of the file.
  1386.  *          If the start of the file is reached, then movement stops.
  1387.  */
  1388. int  page_up( WINDOW *window )
  1389. {
  1390. int  i;                 /* count of lines scanned */
  1391. int  rc = OK;           /* default return code */
  1392. register WINDOW *win;   /* put window pointer in a register */
  1393. long number;
  1394. long len;
  1395.  
  1396.    win = window;
  1397.    entab_linebuff( );
  1398.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1399.       return( ERROR );
  1400.    if (win->rline != (win->cline - (win->top_line + win->ruler - 1))) {
  1401.       i = win->cline - (win->top_line + win->ruler - 1);
  1402.       number = win->rline;
  1403.       if (( win->rline - i) < win->page)
  1404.          win->rline = (win->cline-(win->top_line + win->ruler -1)) + win->page;
  1405.       win->rline -= win->page;
  1406.       for (len =0, i=(int)(number - win->rline); i>0; i--)
  1407.          if (win->ll->prev != NULL) {
  1408.             win->ll = win->ll->prev;
  1409.             len -= win->ll->len;
  1410.          }
  1411.       win->file_info->dirty = LOCAL;
  1412.       win->bin_offset += len;
  1413.    } else
  1414.       rc = ERROR;
  1415.    sync( win );
  1416.    return( rc );
  1417. }
  1418.  
  1419.  
  1420. /*
  1421.  * Name:    page_down
  1422.  * Purpose: To move the cursor one page down the window
  1423.  * Date:    June 5, 1991
  1424.  * Passed:  window:  pointer to current window
  1425.  * Notes:   The cursor line is moved forwards the required number of lines
  1426.  *           towards the end of the file.
  1427.  *          If the end of the file is reached, then movement stops.
  1428.  */
  1429. int  page_down( WINDOW *window )
  1430. {
  1431. int  i;                 /* count of lines scanned so far */
  1432. int  k;
  1433. int  rc = OK;
  1434. long len;
  1435. register WINDOW *win;  /* put window pointer in a register */
  1436. line_list_ptr p;
  1437.  
  1438.    win = window;
  1439.    entab_linebuff( );
  1440.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1441.       return( ERROR );
  1442.    p = win->ll;
  1443.    k = win->cline - (win->top_line + win->ruler);
  1444.    for (len=i=0; i < win->page && p->next != NULL; i++, k++, p=p->next)
  1445.       if (p->len != EOF)
  1446.          len += p->len;
  1447.    if (k >= win->page) {
  1448.       win->rline += i;
  1449.       win->cline = win->cline + i - win->page;
  1450.       win->bin_offset += len;
  1451.       win->ll = p;
  1452.       win->file_info->dirty = LOCAL;
  1453.    } else
  1454.       rc = ERROR;
  1455.    sync( win );
  1456.    return( rc );
  1457. }
  1458.  
  1459.  
  1460. /*
  1461.  * Name:    scroll_down
  1462.  * Purpose: scroll window down one line
  1463.  * Date:    June 5, 1991
  1464.  * Passed:  window:  pointer to current window
  1465.  * Notes:   If there is a line to scroll_down, make the window LOCAL dirty.
  1466.  *          We have to redraw the screen anyway, so don't update here.
  1467.  */
  1468. int  scroll_down( WINDOW *window )
  1469. {
  1470. int  rc = OK;
  1471. register WINDOW *win;   /* put window pointer in a register */
  1472.  
  1473.    win = window;
  1474.    entab_linebuff( );
  1475.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1476.       return( ERROR );
  1477.    if (win->cline == win->top_line + win->ruler) {
  1478.       if (win->ll->next != NULL) {
  1479.          ++win->rline;
  1480.          win->bin_offset += win->ll->len;
  1481.          win->ll = win->ll->next;
  1482.          win->file_info->dirty = LOCAL;
  1483.       } else
  1484.          rc = ERROR;
  1485.    } else {
  1486.       --win->cline;
  1487.       win->file_info->dirty = LOCAL;
  1488.    }
  1489.    sync( win );
  1490.    return( rc );
  1491. }
  1492.  
  1493.  
  1494. /*
  1495.  * Name:    scroll_up
  1496.  * Purpose: To scroll the window up one line
  1497.  * Date:    June 5, 1991
  1498.  * Passed:  window:  pointer to current window
  1499.  * Notes:   If this is the first page, then update screen here.  Else, make
  1500.  *           the window LOCAL dirty because we have to redraw screen.
  1501.  */
  1502. int  scroll_up( WINDOW *window )
  1503. {
  1504. int  rc = OK;
  1505. register WINDOW *win;   /* put window pointer in a register */
  1506.  
  1507.    win = window;
  1508.    entab_linebuff( );
  1509.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1510.       return( ERROR );
  1511.    if (win->rline > 1) {
  1512.       if (win->rline == (win->cline - (win->top_line + win->ruler - 1))) {
  1513.          if (!mode.sync)
  1514.             update_line( win );
  1515.          win->ll = win->ll->prev;
  1516.          win->bin_offset -= win->ll->len;
  1517.          --win->rline;
  1518.          --win->cline;
  1519.          if (!mode.sync)
  1520.             show_curl_line( win );
  1521.       } else {
  1522.          if (win->cline == win->bottom_line) {
  1523.             --win->rline;
  1524.             win->ll = win->ll->prev;
  1525.             win->bin_offset -= win->ll->len;
  1526.             win->file_info->dirty = LOCAL;
  1527.          } else {
  1528.             ++win->cline;
  1529.             win->file_info->dirty = LOCAL;
  1530.          }
  1531.       }
  1532.    } else
  1533.      rc = ERROR;
  1534.    sync( win );
  1535.    return( rc );
  1536. }
  1537.  
  1538.  
  1539. /*
  1540.  * Name:    pan_up
  1541.  * Purpose: To leave cursor on same logical line and scroll text up
  1542.  * Date:    September 1, 1991
  1543.  * Passed:  window:  pointer to current window
  1544.  * Notes:   If cursor is on first page then do not scroll.
  1545.  */
  1546. int  pan_up( WINDOW *window )
  1547. {
  1548. int  rc = OK;
  1549. register WINDOW *win;   /* put window pointer in a register */
  1550.  
  1551.    win = window;
  1552.    entab_linebuff( );
  1553.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1554.       return( ERROR );
  1555.  
  1556.    /*
  1557.     * see if cursor is on the first page. if it's not then pan_up.
  1558.     */
  1559.    if (win->rline != (win->cline+1 - (win->top_line + win->ruler))) {
  1560.       if (win->rline > 1) {
  1561.          --win->rline;
  1562.          win->ll = win->ll->prev;
  1563.          win->bin_offset -= win->ll->len;
  1564.          win->file_info->dirty = LOCAL;
  1565.       }
  1566.    } else
  1567.       rc = ERROR;
  1568.    sync( win );
  1569.    return( rc );
  1570. }
  1571.  
  1572.  
  1573. /*
  1574.  * Name:    pan_down
  1575.  * Purpose: To leave cursor on same logical line and scroll text down
  1576.  * Date:    September 1, 1991
  1577.  * Passed:  window:  pointer to current window
  1578.  * Notes:   If cursor is on last line in file then do not scroll.
  1579.  */
  1580. int  pan_down( WINDOW *window )
  1581. {
  1582. int  rc = OK;
  1583. register WINDOW *win;   /* put window pointer in a register */
  1584.  
  1585.    win = window;
  1586.    entab_linebuff( );
  1587.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1588.       return( ERROR );
  1589.    if (win->ll->len != EOF) {
  1590.       ++win->rline;
  1591.       win->bin_offset += win->ll->len;
  1592.       win->ll = win->ll->next;
  1593.       win->file_info->dirty = LOCAL;
  1594.    } else
  1595.       rc = ERROR;
  1596.    sync( win );
  1597.    return( rc );
  1598. }
  1599.  
  1600.  
  1601. /*
  1602.  * Name:    show_window_header
  1603.  * Purpose: show file stuff in window header
  1604.  * Date:    June 5, 1991
  1605.  * Passed:  window:  pointer to current window
  1606.  * Notes:   Clear line and display header in a lite bar
  1607.  */
  1608. void show_window_header( WINDOW *window )
  1609. {
  1610. char status_line[MAX_COLS+2];   /* status line at top of window */
  1611. register WINDOW *win;           /* put window pointer in a register */
  1612. int  len;
  1613.  
  1614.    win = window;
  1615.    len = win->vertical ? win->end_col + 1 - win->start_col : win->end_col;
  1616.  
  1617.    assert( len >= 0 );
  1618.    assert( len <= MAX_COLS );
  1619.  
  1620.    memset( status_line, ' ', len );
  1621.    status_line[len] = '\0';
  1622.    s_output( status_line, win->top_line-1, win->start_col,g_display.head_color);
  1623.    show_window_number_letter( win );
  1624.    show_window_fname( win );
  1625.    show_crlf_mode( win );
  1626.    show_size( win );
  1627.    show_line_col( win );
  1628. }
  1629.  
  1630.  
  1631. /*
  1632.  * Name:    show_window_number_letter
  1633.  * Purpose: show file number and letter of window in lite bar
  1634.  * Date:    June 5, 1991
  1635.  * Passed:  window:  pointer to current window
  1636.  */
  1637. void show_window_number_letter( WINDOW *window )
  1638. {
  1639. int  col;
  1640. char temp[10];
  1641. register WINDOW *win;   /* put window pointer in a register */
  1642.  
  1643.    win = window;
  1644.    col = win->start_col;
  1645.    s_output( "   ", win->top_line-1, col, g_display.head_color );
  1646.    itoa( win->file_info->file_no, temp, 10 );
  1647.    s_output( temp, win->top_line-1, strlen( temp ) > 1 ? col : col+1,
  1648.              g_display.head_color );
  1649.    c_output( win->letter, col+2, win->top_line-1, g_display.head_color );
  1650. }
  1651.  
  1652.  
  1653. /*
  1654.  * Name:    show_window_fname
  1655.  * Purpose: show file name in window header.
  1656.  * Date:    June 5, 1991
  1657.  * Passed:  window:  pointer to current window
  1658.  * Notes:   Clear name field and display name in a lite bar
  1659.  */
  1660. void show_window_fname( WINDOW *window )
  1661. {
  1662. char status_line[MAX_COLS+2];   /* status line at top of window */
  1663. register int  fattr;
  1664. char *p;
  1665. register WINDOW *win;          /* put window pointer in a register */
  1666. int  col;
  1667. int  len;
  1668.  
  1669.    win = window;
  1670.    col = win->start_col;
  1671.    len = win->vertical ? 11 : FNAME_LENGTH;
  1672.  
  1673.    assert( len >= 0 );
  1674.    assert( len <= MAX_COLS );
  1675.  
  1676.    memset( status_line, ' ', len );
  1677.    status_line[len] = '\0';
  1678.    s_output( status_line, win->top_line-1, col+5, g_display.head_color );
  1679.  
  1680.    assert( strlen( win->file_info->file_name ) < MAX_COLS );
  1681.  
  1682.    strcpy( status_line, win->file_info->file_name );
  1683.    p = status_line;
  1684.    if (win->vertical) {
  1685.       len = strlen( status_line );
  1686.       for (p=status_line+len;*(p-1) != ':' && *(p-1) != '\\' && p>status_line;)
  1687.          --p;
  1688.    } else {
  1689.       status_line[FNAME_LENGTH] = '\0';
  1690.       p = status_line;
  1691.    }
  1692.    s_output( p, win->top_line-1, col+5, g_display.head_color );
  1693.    if (!win->vertical) {
  1694.       fattr = win->file_info->file_attrib;
  1695.       p = status_line;
  1696.       *p++ = (char)(fattr & ARCHIVE   ? 'A' : '-');
  1697.       *p++ = (char)(fattr & SYSTEM    ? 'S' : '-');
  1698.       *p++ = (char)(fattr & HIDDEN    ? 'H' : '-');
  1699.       *p++ = (char)(fattr & READ_ONLY ? 'R' : '-');
  1700.       *p   = '\0';
  1701.       s_output( status_line, win->top_line-1, col+51, g_display.head_color );
  1702.    }
  1703. }
  1704.  
  1705.  
  1706. /*
  1707.  * Name:    show_crlf_mode
  1708.  * Purpose: display state of crlf flag
  1709.  * Date:    June 5, 1991
  1710.  */
  1711. void show_crlf_mode( WINDOW *window )
  1712. {
  1713. char status_line[MAX_COLS+2];   /* status line at top of window */
  1714.  
  1715.    if (!window->vertical) {
  1716.       switch (window->file_info->crlf) {
  1717.          case LF :
  1718.             strcpy( status_line, "lf  " );
  1719.             break;
  1720.          case CRLF :
  1721.             strcpy( status_line, "crlf" );
  1722.             break;
  1723.          case BINARY :
  1724.             strcpy( status_line, "BIN " );
  1725.             break;
  1726.          default :
  1727.             assert( FALSE );
  1728.       }
  1729.       s_output( status_line, window->top_line-1, window->start_col+56,
  1730.                 g_display.head_color );
  1731.    }
  1732. }
  1733.  
  1734.  
  1735. /*
  1736.  * Name:    show_size
  1737.  * Purpose: show number of lines in file
  1738.  * Date:    June 5, 1991
  1739.  * Passed:  window:  pointer to current window
  1740.  */
  1741. void show_size( WINDOW *window )
  1742. {
  1743. char csize[20];
  1744.  
  1745.    if (!window->vertical  &&  window->file_info->crlf != BINARY) {
  1746.       s_output( "       ", window->top_line-1, 61, g_display.head_color );
  1747.       ltoa( window->file_info->length, csize, 10 );
  1748.       s_output( csize, window->top_line-1, 61, g_display.head_color );
  1749.    }
  1750. }
  1751.  
  1752.  
  1753. /*
  1754.  * Name:    quit
  1755.  * Purpose: To close the current window without saving the current file.
  1756.  * Date:    June 5, 1991
  1757.  * Passed:  window:  pointer to current window
  1758.  * Notes:   If the file has been modified but not saved, then the user is
  1759.  *           given a second chance before the changes are discarded.
  1760.  *          Note that this is only necessary if this is the last window
  1761.  *           that refers to the file.  If another window still refers to
  1762.  *           the file, then the check can be left until later.
  1763.  */
  1764. int  quit( WINDOW *window )
  1765. {
  1766. int  prompt_line;
  1767. char line_buff[(MAX_COLS+2)*2]; /* buffer for char and attribute  */
  1768. register file_infos *file;
  1769. WINDOW *wp;
  1770. int  count = 0;
  1771. int  rc = OK;
  1772.  
  1773.    entab_linebuff( );
  1774.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  1775.       return( ERROR );
  1776.    prompt_line = window->bottom_line;
  1777.    file = window->file_info;
  1778.    for (wp=g_status.window_list; wp != NULL; wp=wp->next) {
  1779.       if (wp->file_info == file && wp->visible)
  1780.          ++count;
  1781.    }
  1782.    if (file->modified && count == 1) {
  1783.       save_screen_line( 0, prompt_line, line_buff );
  1784.       /*
  1785.        * abandon changes (y/n)
  1786.        */
  1787.       set_prompt( utils12, prompt_line );
  1788.       if (get_yn( ) != A_YES)
  1789.          rc = ERROR;
  1790.       restore_screen_line( 0, prompt_line, line_buff );
  1791.    }
  1792.  
  1793.    /*
  1794.     * remove window, allocate screen lines to other windows etc
  1795.     */
  1796.    if (rc == OK)
  1797.       finish( window );
  1798.    return( OK );
  1799. }
  1800.  
  1801.  
  1802. /*
  1803.  * Name:    move_up
  1804.  * Purpose: To move the cursor up one line
  1805.  * Date:    June 5, 1991
  1806.  * Passed:  window:  pointer to current window
  1807.  * Notes:   If the cursor is at the top of the window, then the file must
  1808.  *           be scrolled down.
  1809.  */
  1810. int  move_up( WINDOW *window )
  1811. {
  1812. int  rc = OK;
  1813. register WINDOW *win;   /* put window pointer in a register */
  1814. int  at_top = FALSE;    /* is cline at top of screen? */
  1815.  
  1816.    win = window;
  1817.    entab_linebuff( );
  1818.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1819.       return( ERROR );
  1820.  
  1821.    /*
  1822.     * if no previous line, give up
  1823.     */
  1824.    if (win->rline > 1) {
  1825.       if (win->cline == win->top_line + win->ruler) {
  1826.          win->file_info->dirty = LOCAL;
  1827.          at_top = TRUE;
  1828.       }
  1829.       if (!at_top)
  1830.          update_line( win );
  1831.       --win->rline;             /* ALWAYS decrement line counter */
  1832.       win->ll = win->ll->prev;
  1833.       win->bin_offset -= win->ll->len;
  1834.       if (!at_top) {
  1835.          --win->cline;          /* we aren't at top of screen - so move up */
  1836.          show_curl_line( win );
  1837.       }
  1838.    } else
  1839.       rc = ERROR;
  1840.    sync( win );
  1841.    return( rc );
  1842. }
  1843.  
  1844.  
  1845. /*
  1846.  * Name:    move_down
  1847.  * Purpose: To move the cursor down one line
  1848.  * Date:    June 5, 1991
  1849.  * Passed:  window:  pointer to current window
  1850.  * Notes:   If the cursor is at the bottom of the window, then the file must
  1851.  *           be scrolled up.   If the cursor is at the bottom of the file,
  1852.  *           then scroll line up until it is at top of screen.
  1853.  */
  1854. int  move_down( WINDOW *window )
  1855. {
  1856. int  rc;
  1857.  
  1858.    rc = prepare_move_down( window );
  1859.    sync( window );
  1860.    return( rc );
  1861. }
  1862.  
  1863.  
  1864. /*
  1865.  * Name:    prepare_move_down
  1866.  * Purpose: Do the stuff needed to move the cursor down one line.
  1867.  * Date:    June 5, 1991
  1868.  * Passed:  window:  pointer to current window
  1869.  * Notes:   Put all the stuff needed to move the cursor down one line in
  1870.  *           one function, so several functions can use the guts of the
  1871.  *           algorithm.
  1872.  */
  1873. int  prepare_move_down( WINDOW *window )
  1874. {
  1875. int  rc = OK;
  1876. register WINDOW *win;   /* put window pointer in a register */
  1877. int  at_bottom = FALSE; /* is cline at bottom of screen */
  1878.  
  1879.    win = window;
  1880.    entab_linebuff( );
  1881.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  1882.       return( ERROR );
  1883.    if (win->cline == win->bottom_line) {
  1884.       win->file_info->dirty = LOCAL;
  1885.       at_bottom = TRUE;
  1886.    }
  1887.    if (!at_bottom)
  1888.       update_line( win );
  1889.    if (win->ll->len != EOF) {
  1890.       win->bin_offset += win->ll->len;
  1891.       ++win->rline;             /* ALWAYS increment line counter */
  1892.       win->ll = win->ll->next;
  1893.       if (!at_bottom) {
  1894.          ++win->cline;          /* if not at bottom of screen move down */
  1895.          show_curl_line( win );
  1896.       }
  1897.    } else if (win->cline > win->top_line + win->ruler) {
  1898.       --win->cline;
  1899.       win->file_info->dirty = LOCAL;
  1900.       rc = ERROR;
  1901.    } else
  1902.       rc = ERROR;
  1903.    return( rc );
  1904. }
  1905.  
  1906.  
  1907. /*
  1908.  * Name:    move_left
  1909.  * Purpose: To move the cursor left one character
  1910.  * Date:    June 5, 1991
  1911.  * Passed:  window:  pointer to current window
  1912.  * Notes:   If the cursor is already at the left of the screen, then
  1913.  *           scroll horizontally if we're not at beginning of line.
  1914.  */
  1915. int  move_left( WINDOW *window )
  1916. {
  1917. int  new_ruler = FALSE;
  1918.  
  1919.    if (window->ccol > window->start_col) {
  1920.       show_ruler_char( window );
  1921.       --window->ccol;
  1922.       --window->rcol;
  1923.    } else if (window->ccol == window->start_col && window->rcol > 0) {
  1924.       --window->rcol;
  1925.       --window->bcol;
  1926.       window->file_info->dirty = LOCAL;
  1927.       new_ruler = TRUE;
  1928.    }
  1929.    sync( window );
  1930.    if (new_ruler) {
  1931.       make_ruler( window );
  1932.       show_ruler( window );
  1933.    }
  1934.    return( OK );
  1935. }
  1936.  
  1937.  
  1938. /*
  1939.  * Name:    move_right
  1940.  * Purpose: To move the cursor right one character
  1941.  * Date:    June 5, 1991
  1942.  * Passed:  window:  pointer to current window
  1943.  * Notes:   If the cursor is already at the right of the screen (logical
  1944.  *          column 80) then scroll horizontally right.
  1945.  */
  1946. int  move_right( WINDOW *window )
  1947. {
  1948. int  new_ruler = FALSE;
  1949.  
  1950.    if (window->rcol < g_display.line_length - 1) {
  1951.       if (window->ccol < window->end_col) {
  1952.          show_ruler_char( window );
  1953.          ++window->ccol;
  1954.          ++window->rcol;
  1955.       } else if (window->ccol == window->end_col) {
  1956.          ++window->rcol;
  1957.          ++window->bcol;
  1958.          window->file_info->dirty = LOCAL;
  1959.          new_ruler = TRUE;
  1960.       }
  1961.    }
  1962.    sync( window );
  1963.    if (new_ruler) {
  1964.       make_ruler( window );
  1965.       show_ruler( window );
  1966.    }
  1967.    return( OK );
  1968. }
  1969.  
  1970.  
  1971. /*
  1972.  * Name:    pan_left
  1973.  * Purpose: To pan the screen left one character
  1974.  * Date:    January 5, 1992
  1975.  * Passed:  window:  pointer to current window
  1976.  */
  1977. int  pan_left( WINDOW *window )
  1978. {
  1979. /*
  1980.  * if (window->bcol == 0) {
  1981.  *    if (window->ccol > window->start_col) {
  1982.  *       show_ruler_char( window );
  1983.  *       --window->ccol;
  1984.  *       --window->rcol;
  1985.  *    }
  1986.  * } else if (window->bcol > 0 ) {
  1987.  * * *  Scroll window left function:
  1988.  * * *      --window->bcol;
  1989.  * * *      if (window->ccol < g_display.ncols - 1)
  1990.  * * *         ++window->ccol;
  1991.  * * *      else
  1992.  * * *         --window->rcol;
  1993.  */
  1994.    if (window->bcol > 0 ) {
  1995.       --window->bcol;
  1996.       --window->rcol;
  1997.       window->file_info->dirty = LOCAL;
  1998.       make_ruler( window );
  1999.       show_ruler( window );
  2000.    }
  2001.    sync( window );
  2002.    return( OK );
  2003. }
  2004.  
  2005.  
  2006. /*
  2007.  * Name:    pan_right
  2008.  * Purpose: To pan the screen right one character
  2009.  * Date:    January 5, 1992
  2010.  * Passed:  window:  pointer to current window
  2011.  */
  2012. int  pan_right( WINDOW *window )
  2013. {
  2014.    if (window->rcol < g_display.line_length - 1) {
  2015. /*
  2016.  *      scroll screen right function:
  2017.  *      if (window->ccol > 0)
  2018.  *         --window->ccol;
  2019.  *      else
  2020.  *         ++window->rcol;
  2021.  */
  2022.       ++window->rcol;
  2023.       ++window->bcol;
  2024.       window->file_info->dirty = LOCAL;
  2025.       make_ruler( window );
  2026.       show_ruler( window );
  2027.    }
  2028.    sync( window );
  2029.    return( OK );
  2030. }
  2031.  
  2032.  
  2033. /*
  2034.  * Name:    word_left
  2035.  * Purpose: To move the cursor left one word
  2036.  * Date:    June 5, 1991
  2037.  * Passed:  window:  pointer to current window
  2038.  * Notes:   Words are considered strings of letters, numbers and underscores,
  2039.  *          which must be separated by other characters.
  2040.  */
  2041. int  word_left( WINDOW *window )
  2042. {
  2043. text_ptr p;             /* text pointer */
  2044. int  len;               /* length of current line */
  2045. int  rc;
  2046. register int rcol;
  2047. long rline;
  2048. line_list_ptr ll;
  2049. WINDOW w;
  2050.  
  2051.    entab_linebuff( );
  2052.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2053.       return( ERROR );
  2054.    rc = OK;
  2055.    dup_window_info( &w, window );
  2056.    rline = window->rline;
  2057.    rcol  = window->rcol;
  2058.    ll = window->ll;
  2059.    if (ll->len != EOF) {
  2060.       p = ll->line;
  2061.       len = ll->len;
  2062.  
  2063.       if (p != NULL  &&  rcol > 0  &&  rcol >= len  &&
  2064.                                       !myiswhitespc( *(p + len - 1) )) {
  2065.          rcol = len - 1;
  2066.          p += rcol;
  2067.          for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2068.          ++rcol;
  2069.          check_virtual_col( window, rcol, rcol );
  2070.          make_ruler( window );
  2071.          show_ruler( window );
  2072.       } else {
  2073.          rcol = rcol >= len ? len-1 : rcol;
  2074.          if (rcol >= 0)
  2075.             p += rcol;
  2076.          if (p != NULL  &&  rcol > 0  &&  !myiswhitespc( *p )  &&
  2077.                                           !myiswhitespc( *(p-1) )) {
  2078.             for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2079.             ++rcol;
  2080.             check_virtual_col( window, rcol, rcol );
  2081.             make_ruler( window );
  2082.             show_ruler( window );
  2083.          } else {
  2084.  
  2085.             /*
  2086.              * if we are on the first letter of a word, get off.
  2087.              */
  2088.             if (p != NULL)
  2089.                for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2090.  
  2091.             /*
  2092.              * go to the next line if word begins at 1st col in line.
  2093.              */
  2094.             if (rcol < 0) {
  2095.                if (ll->prev != NULL) {
  2096.                   --rline;
  2097.                   ll = ll->prev;
  2098.                   p = ll->line;
  2099.                   rcol = ll->len - 1;
  2100.                   if (rcol >= 0)
  2101.                      p += rcol;
  2102.                } else
  2103.                   rc = ERROR;
  2104.             }
  2105.  
  2106.             /*
  2107.              * skip all blanks until we get to a previous word
  2108.              */
  2109.             while (rc == OK  &&  (p == NULL  ||  (p != NULL  &&
  2110.                                                   myiswhitespc( *p )))) {
  2111.                for (; rcol >= 0 && myiswhitespc( *p ); rcol--, p--);
  2112.                if (rcol < 0) {
  2113.                   if (ll->prev != NULL) {
  2114.                      --rline;
  2115.                      ll = ll->prev;
  2116.                      p = ll->line;
  2117.                      rcol = ll->len - 1;
  2118.                      if (rcol >= 0)
  2119.                         p += rcol;
  2120.                   } else
  2121.                      rc = ERROR;
  2122.                } else
  2123.                   break;
  2124.             }
  2125.  
  2126.             /*
  2127.              * now, find the beginning of the word.
  2128.              */
  2129.             if (rc == OK  &&  p != NULL) {
  2130.                for (; rcol >= 0 && !myiswhitespc( *p ); rcol--, p--);
  2131.                bin_offset_adjust( window, rline );
  2132.                find_adjust( window, ll, rline, rcol+1 );
  2133.                if (rline != w.rline && !window->file_info->dirty) {
  2134.                   update_line( &w );
  2135.                   show_curl_line( window );
  2136.                }
  2137.                make_ruler( window );
  2138.                show_ruler( window );
  2139.             } else
  2140.                rc = ERROR;
  2141.          }
  2142.       }
  2143.    } else
  2144.       rc = ERROR;
  2145.  
  2146.    sync( window );
  2147.    return( rc );
  2148. }
  2149.  
  2150.  
  2151. /*
  2152.  * Name:    word_right
  2153.  * Purpose: To move the cursor right one word
  2154.  * Date:    June 5, 1991
  2155.  * Passed:  window:  pointer to current window
  2156.  * Notes:   Words are considered strings of letters, numbers and underscores,
  2157.  *           which must be separated by other characters.
  2158.  */
  2159. int  word_right( WINDOW *window )
  2160. {
  2161. int  len;               /* length of current line */
  2162. text_ptr p;             /* text pointer */
  2163. int  rc;
  2164. WINDOW w;
  2165. register int rcol;
  2166. line_list_ptr ll;
  2167. long rline;
  2168.  
  2169.    entab_linebuff( );
  2170.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2171.       return( ERROR );
  2172.    rc = OK;
  2173.    dup_window_info( &w, window );
  2174.    rline = window->rline;
  2175.    rcol  = window->rcol;
  2176.    ll = window->ll;
  2177.    if (ll->len != EOF) {
  2178.       p = ll->line;
  2179.       len = ll->len;
  2180.  
  2181.       /*
  2182.        * if rcol is past EOL, move it to EOL
  2183.        */
  2184.       rcol = rcol >= len ? len-1 : rcol;
  2185.       if (rcol >= 0)
  2186.          p += rcol;
  2187.  
  2188.       /*
  2189.        * if cursor is on a word, find end of word.
  2190.        */
  2191.       if (p != NULL)
  2192.          for (; rcol < len && !myiswhitespc( *p ); rcol++, p++);
  2193.       else
  2194.          rcol = len;
  2195.  
  2196.       /*
  2197.        * go to the next line if word ends at eol.
  2198.        */
  2199.       if (rcol == len) {
  2200.          ++rline;
  2201.          ll = ll->next;
  2202.          if (ll->len != EOF) {
  2203.             p = ll->line;
  2204.             len = ll->len;
  2205.             rcol = 0;
  2206.          } else
  2207.             rc = ERROR;
  2208.       }
  2209.  
  2210.       /*
  2211.        * now, go forward thru the file looking for the first letter of word.
  2212.        */
  2213.       while (rc == OK && (p == NULL  ||  (p != NULL && myiswhitespc( *p )))) {
  2214.          for (; rcol < len && myiswhitespc( *p ); rcol++, p++);
  2215.          if (rcol == len) {
  2216.             ++rline;
  2217.             ll = ll->next;
  2218.             if (ll->len != EOF) {
  2219.                p = ll->line;
  2220.                len = ll->len;
  2221.                rcol = 0;
  2222.             } else
  2223.                rc = ERROR;
  2224.          } else
  2225.             break;
  2226.       }
  2227.    } else
  2228.       rc = ERROR;
  2229.  
  2230.    if (rc == OK) {
  2231.       bin_offset_adjust( window, rline );
  2232.       find_adjust( window, ll, rline, rcol );
  2233.       make_ruler( window );
  2234.       show_ruler( window );
  2235.    }
  2236.  
  2237.    if (rline != w.rline && !window->file_info->dirty) {
  2238.       update_line( &w );
  2239.       show_curl_line( window );
  2240.    }
  2241.    sync( window );
  2242.    return( rc );
  2243. }
  2244.  
  2245.  
  2246. /*
  2247.  * Name:    next_dirty_line
  2248.  * Purpose: To move the cursor to the next dirty line, if it exists
  2249.  * Date:    April 1, 1993
  2250.  * Passed:  window:  pointer to current window
  2251.  */
  2252. int  next_dirty_line( WINDOW *window )
  2253. {
  2254. int  rc;
  2255. line_list_ptr ll;
  2256. long rline;
  2257. long bin_offset;       /* binary offset */
  2258. WINDOW w;
  2259.  
  2260.    entab_linebuff( );
  2261.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2262.       return( ERROR );
  2263.    rc = OK;
  2264.    dup_window_info( &w, window );
  2265.    rline = window->rline;
  2266.    ll = window->ll;
  2267.    bin_offset = window->bin_offset;
  2268.    if (ll->len != EOF) {
  2269.       while (rc == OK) {
  2270.          if (ll->len != EOF) {
  2271.             ++rline;
  2272.             bin_offset += ll->len;
  2273.             ll = ll->next;
  2274.             if (ll->dirty == TRUE)
  2275.                break;
  2276.          } else
  2277.             rc = ERROR;
  2278.       }
  2279.    } else
  2280.       rc = ERROR;
  2281.  
  2282.    if (rc == OK) {
  2283.       window->bin_offset = bin_offset;
  2284.       find_adjust( window, ll, rline, window->rcol );
  2285.       make_ruler( window );
  2286.       show_ruler( window );
  2287.    } else
  2288.       error( WARNING, window->bottom_line, utils16 );
  2289.  
  2290.    if (rline != w.rline && !window->file_info->dirty) {
  2291.       update_line( &w );
  2292.       show_curl_line( window );
  2293.    }
  2294.    sync( window );
  2295.    return( rc );
  2296. }
  2297.  
  2298.  
  2299. /*
  2300.  * Name:    prev_dirty_line
  2301.  * Purpose: To move the cursor to the prev dirty line, if it exists
  2302.  * Date:    April 1, 1993
  2303.  * Passed:  window:  pointer to current window
  2304.  */
  2305. int  prev_dirty_line( WINDOW *window )
  2306. {
  2307. int  rc;
  2308. line_list_ptr ll;
  2309. long rline;
  2310. long bin_offset;        /* binary offset */
  2311. WINDOW w;
  2312.  
  2313.    entab_linebuff( );
  2314.    if (un_copy_line( window->ll, window, TRUE ) == ERROR)
  2315.       return( ERROR );
  2316.    rc = OK;
  2317.    dup_window_info( &w, window );
  2318.    rline = window->rline;
  2319.    ll = window->ll;
  2320.    bin_offset = window->bin_offset;
  2321.    if (ll->prev != NULL) {
  2322.       while (rc == OK) {
  2323.          if (ll->prev != NULL) {
  2324.             --rline;
  2325.             ll = ll->prev;
  2326.             bin_offset -= ll->len;
  2327.             if (ll->dirty == TRUE)
  2328.                break;
  2329.          } else
  2330.             rc = ERROR;
  2331.       }
  2332.    } else
  2333.       rc = ERROR;
  2334.  
  2335.    if (rc == OK) {
  2336.       window->bin_offset = bin_offset;
  2337.       find_adjust( window, ll, rline, window->rcol );
  2338.       make_ruler( window );
  2339.       show_ruler( window );
  2340.    } else
  2341.       error( WARNING, window->bottom_line, utils16 );
  2342.  
  2343.    if (rline != w.rline && !window->file_info->dirty) {
  2344.       update_line( &w );
  2345.       show_curl_line( window );
  2346.    }
  2347.    sync( window );
  2348.    return( rc );
  2349. }
  2350.  
  2351.  
  2352. /*
  2353.  * Name:    center_window
  2354.  * Purpose: To place the current line or cursor in the center of a window.
  2355.  * Date:    June 5, 1991
  2356.  * Passed:  window:  pointer to current window
  2357.  */
  2358. int  center_window( WINDOW *window )
  2359. {
  2360. int  center;
  2361. int  center_line;
  2362. int  diff;
  2363. register file_infos *file;
  2364. register WINDOW *win;           /* put window pointer in a register */
  2365.  
  2366.    win = window;
  2367.    file = win->file_info;
  2368.    center = (win->bottom_line + 1 - win->top_line) / 2 - win->ruler;
  2369.    center_line = win->top_line + win->ruler + center;
  2370.    diff = center_line - win->cline;
  2371.    entab_linebuff( );
  2372.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2373.       return( ERROR );
  2374.    if (g_status.command == CenterWindow) {
  2375.       if (diff > 0) {
  2376.          if (win->rline + diff <= file->length) {
  2377.             update_line( win );
  2378.             win->cline += diff;
  2379.             win->rline += diff;
  2380.             for (; diff > 0; diff--) {
  2381.                win->bin_offset += win->ll->len;
  2382.                win->ll = win->ll->next;
  2383.             }
  2384.             show_curl_line( win );
  2385.          }
  2386.       } else if (diff < 0) {
  2387.          update_line( win );
  2388.          win->cline += diff;
  2389.          win->rline += diff;
  2390.          for (; diff < 0; diff++) {
  2391.             win->ll = win->ll->prev;
  2392.             win->bin_offset -= win->ll->len;
  2393.          }
  2394.          show_curl_line( win );
  2395.       }
  2396.    } else {
  2397.       if (diff > 0) {
  2398.          win->cline += diff;
  2399.          if ((long)(win->cline+1 - (win->top_line + win->ruler)) > win->rline)
  2400.             win->cline = (win->top_line + win->ruler) - 1 + (int)win->rline;
  2401.          file->dirty = LOCAL;
  2402.       } else if (diff < 0) {
  2403.          win->cline = win->cline + diff;
  2404.          file->dirty = LOCAL;
  2405.       }
  2406.    }
  2407.    if (g_status.command == CenterWindow  ||  g_status.command == CenterLine)
  2408.       sync( win );
  2409.    return( OK );
  2410. }
  2411.  
  2412.  
  2413. /*
  2414.  * Name:    horizontal_screen_right
  2415.  * Purpose: To move the cursor one screen to the right
  2416.  * Date:    September 13, 1991
  2417.  * Passed:  window:  pointer to current window
  2418.  * Notes:   Add 80 columns to the real cursor.  If the cursor is past the
  2419.  *          maximum line length then move it back.
  2420.  */
  2421. int  horizontal_screen_right( WINDOW *window )
  2422. {
  2423. int  col;
  2424.  
  2425.    col = window->rcol;
  2426.    col += (window->end_col + 1 - window->start_col);
  2427.    if (col < MAX_LINE_LENGTH) {
  2428.       window->rcol = col;
  2429.       window->bcol += (window->end_col + 1 - window->start_col);
  2430.       window->file_info->dirty = LOCAL;
  2431.       check_virtual_col( window, window->rcol, window->ccol );
  2432.       make_ruler( window );
  2433.       show_ruler( window );
  2434.    }
  2435.    sync( window );
  2436.    return( OK );
  2437. }
  2438.  
  2439.  
  2440. /*
  2441.  * Name:    horizontal_screen_left
  2442.  * Purpose: To move the cursor one screen to the left
  2443.  * Date:    September 13, 1991
  2444.  * Passed:  window:  pointer to current window
  2445.  * Notes:   Subtract screen width from the real cursor.  If the cursor is less
  2446.  *           than zero then see if bcol is zero.  If bcol is not zero then make
  2447.  *           bcol zero.
  2448.  */
  2449. int  horizontal_screen_left( WINDOW *window )
  2450. {
  2451. int  screen_width;
  2452.  
  2453.    screen_width = window->end_col + 1 - window->start_col;
  2454.    if (window->rcol - screen_width < 0) {
  2455.       if (window->bcol != 0) {
  2456.          window->bcol = 0;
  2457.          window->file_info->dirty = LOCAL;
  2458.       }
  2459.    } else {
  2460.       window->rcol -= screen_width;
  2461.       window->bcol -= screen_width;
  2462.       if (window->bcol < 0)
  2463.          window->bcol = 0;
  2464.       window->file_info->dirty = LOCAL;
  2465.    }
  2466.    check_virtual_col( window, window->rcol, window->ccol );
  2467.    sync( window );
  2468.    make_ruler( window );
  2469.    show_ruler( window );
  2470.    return( OK );
  2471. }
  2472.  
  2473.  
  2474. /*
  2475.  * Name:    goto_top_file
  2476.  * Purpose: To move the cursor to the top of the file.
  2477.  * Date:    June 5, 1991
  2478.  * Passed:  window:  pointer to current window
  2479.  */
  2480. int  goto_top_file( WINDOW *window )
  2481. {
  2482. register WINDOW *win;   /* put window pointer in a register */
  2483. long num;
  2484.  
  2485.    win = window;
  2486.    entab_linebuff( );
  2487.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2488.       return( ERROR );
  2489.    if (win->rline != win->cline - (win->top_line+win->ruler-1)) {
  2490.       win->bin_offset = 0;
  2491.       win->rline = win->cline - (win->top_line+win->ruler-1);
  2492.       win->ll = win->file_info->line_list;
  2493.       for (num=1; num < win->rline; num++) {
  2494.          win->bin_offset += win->ll->len;
  2495.          win->ll = win->ll->next;
  2496.       }
  2497.       display_current_window( win );
  2498.    }
  2499.    sync( win );
  2500.    return( OK );
  2501. }
  2502.  
  2503.  
  2504. /*
  2505.  * Name:    goto_end_file
  2506.  * Purpose: To move the cursor to the end of the file.
  2507.  * Date:    June 5, 1991
  2508.  * Passed:  window:  pointer to current window
  2509.  */
  2510. int  goto_end_file( WINDOW *window )
  2511. {
  2512. register WINDOW *win;  /* put window pointer in a register */
  2513. line_list_ptr ll;
  2514. long length;
  2515.  
  2516.    win = window;
  2517.    entab_linebuff( );
  2518.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2519.       return( ERROR );
  2520.    length = win->file_info->length;
  2521.    if (length > win->rline + win->bottom_line - win->cline) {
  2522.       win->rline = length - (win->bottom_line - win->cline) + 1;
  2523.       win->ll = win->file_info->line_list_end;
  2524.       for (;length >= win->rline; length--)
  2525.          win->ll = win->ll->prev;
  2526.  
  2527.       win->bin_offset = 0;
  2528.       ll = win->file_info->line_list;
  2529.       for (length = 1; length < win->rline; length++) {
  2530.          win->bin_offset += ll->len;
  2531.          ll = ll->next;
  2532.       }
  2533.  
  2534.       display_current_window( win );
  2535.    }
  2536.    sync( win );
  2537.    return( OK );
  2538. }
  2539.  
  2540.  
  2541. /*
  2542.  * Name:    goto_line
  2543.  * Purpose: To move the cursor to a particular line in the file
  2544.  * Date:    June 5, 1991
  2545.  * Passed:  window:  pointer to current window
  2546.  */
  2547. int  goto_line( WINDOW *window )
  2548. {
  2549. long number;            /* line number selected */
  2550. long n;
  2551. char num_str[MAX_COLS]; /* line number as string */
  2552. register WINDOW *win;   /* put window pointer in a register */
  2553. line_list_ptr ll;
  2554. int  rc;
  2555.  
  2556.    win = window;
  2557.    entab_linebuff( );
  2558.    if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2559.       return( ERROR );
  2560.    /*
  2561.     * find out where we are going
  2562.     */
  2563.    num_str[0] = '\0';
  2564.    /*
  2565.     * line number:
  2566.     */
  2567.    if (get_name( find11, win->bottom_line, num_str,
  2568.                  g_display.message_color ) != OK  ||  *num_str == '\0')
  2569.       return( ERROR );
  2570.    number = atol( num_str );
  2571.  
  2572.    if (number > 0  && number <= (long)win->file_info->length) {
  2573.       update_line( win );
  2574.       ll = win->ll;
  2575.       n = win->rline;
  2576.       if (number < win->rline) {
  2577.          if (n - number < number - 1) {
  2578.             for (; n > number; n--) {
  2579.                ll = ll->prev;
  2580.                win->bin_offset -= ll->len;
  2581.             }
  2582.          } else {
  2583.             ll = win->file_info->line_list;
  2584.             n = 1;
  2585.             for (; n < number; n++) {
  2586.                win->bin_offset += ll->len;
  2587.                ll = ll->next;
  2588.             }
  2589.          }
  2590.       } else if (number > win->rline) {
  2591.          for (; n < number; n++) {
  2592.             win->bin_offset += ll->len;
  2593.             ll = ll->next;
  2594.          }
  2595.       }
  2596.       find_adjust( win, ll, number, win->rcol );
  2597.       if (!win->file_info->dirty)
  2598.          show_curl_line( win );
  2599.       rc = OK;
  2600.    } else {
  2601.       /*
  2602.        * out of range.  must be in the range 1 -
  2603.        */
  2604.       strcat( num_str, find12 );
  2605.       ltoa( win->file_info->length, num_str+25, 10 );
  2606.       error( WARNING, win->bottom_line, num_str );
  2607.       rc = ERROR;
  2608.    }
  2609.    return( rc );
  2610. }
  2611.  
  2612.  
  2613. /*
  2614.  * Name:    set_marker
  2615.  * Purpose: To set file marker
  2616.  * Date:    December 28, 1991
  2617.  * Passed:  window:  pointer to current window
  2618.  */
  2619. int  set_marker( WINDOW *window )
  2620. {
  2621. register MARKER  *marker;       /* put the marker in a register */
  2622.  
  2623.    marker = &window->file_info->marker[g_status.command - SetMark1];
  2624.    marker->rline  = window->rline;
  2625.    marker->rcol   = window->rcol;
  2626.    marker->ccol   = window->ccol;
  2627.    marker->bcol   = window->bcol;
  2628.    marker->marked = TRUE;
  2629.    return( OK );
  2630. }
  2631.  
  2632.  
  2633. /*
  2634.  * Name:    goto_marker
  2635.  * Purpose: To goto a file marker
  2636.  * Date:    December 28, 1991
  2637.  * Passed:  window:  pointer to current window
  2638.  */
  2639. int  goto_marker( WINDOW *window )
  2640. {
  2641. int  m;
  2642. file_infos *file;
  2643. long new_rline;
  2644. long n;
  2645. MARKER *marker;
  2646. register WINDOW *win;   /* put window pointer in a register */
  2647. line_list_ptr ll;
  2648. int  rc;
  2649.  
  2650.    win = window;
  2651.    m = g_status.command - GotoMark1;
  2652.    file = win->file_info;
  2653.    marker = &file->marker[m];
  2654.    if (marker->marked) {
  2655.       entab_linebuff( );
  2656.       if (un_copy_line( win->ll, win, TRUE ) == ERROR)
  2657.          return( ERROR );
  2658.       file->dirty = LOCAL;
  2659.       if (marker->rline > file->length)
  2660.          marker->rline = file->length;
  2661.       if (marker->rline < 1l)
  2662.          marker->rline = 1l;
  2663.       new_rline = marker->rline;
  2664.       ll = win->ll;
  2665.       if (new_rline < win->rline) {
  2666.          if (win->rline - new_rline < new_rline - 1) {
  2667.             for (n=win->rline; n > new_rline; n--) {
  2668.                ll = ll->prev;
  2669.                win->bin_offset -= ll->len;
  2670.             }
  2671.          } else {
  2672.             ll = win->file_info->line_list;
  2673.             win->bin_offset = 0;
  2674.             n = 1;
  2675.             for (; n < new_rline; n++) {
  2676.                win->bin_offset += ll->len;
  2677.                ll = ll->next;
  2678.             }
  2679.          }
  2680.       } else if (new_rline > win->rline) {
  2681.          n = win->rline;
  2682.          for (; n < new_rline; n++) {
  2683.             win->bin_offset += ll->len;
  2684.             ll = ll->next;
  2685.          }
  2686.       }
  2687.       win->rline  = new_rline;
  2688.       win->ll     = ll;
  2689.       win->rcol   = marker->rcol;
  2690.       win->ccol   = marker->ccol;
  2691.       win->bcol   = marker->bcol;
  2692.       if (win->rline < (win->cline - ((win->top_line + win->ruler) - 1)))
  2693.          win->cline = (int)win->rline + (win->top_line + win->ruler) - 1;
  2694.       check_virtual_col( win, win->rcol, win->ccol );
  2695.       make_ruler( window );
  2696.       show_ruler( window );
  2697.       rc = OK;
  2698.    } else {
  2699.       if (m == 9)
  2700.          m = -1;
  2701.       *(utils13 + 7) = (char)('0' + m + 1);
  2702.       /*
  2703.        * marker not set
  2704.        */
  2705.       error( WARNING, win->bottom_line, utils13 );
  2706.       rc = ERROR;
  2707.    }
  2708.    return( rc );
  2709. }
  2710.  
  2711.  
  2712. /*
  2713.  * Name:    date_time_stamp
  2714.  * Purpose: put system date and time into file at cursor position
  2715.  * Date:    June 5, 1992
  2716.  * Passed:  window:  pointer to current window
  2717.  */
  2718. int  date_time_stamp( WINDOW *window )
  2719. {
  2720. char date_time[MAX_COLS];
  2721. char stuff[20];
  2722. register char *dt;
  2723. int  year, month, day;
  2724. int  hours, minutes;
  2725. int  one, two, three;
  2726. int  i;
  2727. int  pm;
  2728.  
  2729.  
  2730.    get_date( &year, &month, &day, &i );
  2731.    get_time( &hours, &minutes, &i, &i );
  2732.    dt = date_time;
  2733.  
  2734.    /*
  2735.     * mod year with 100 if needed.
  2736.     */
  2737.    switch (mode.date_style) {
  2738.       case MM_DD_YY  :
  2739.       case DD_MM_YY  :
  2740.       case YY_MM_DD  :
  2741.          year = year % 100;
  2742.    }
  2743.  
  2744.    switch (mode.date_style) {
  2745.       case DD_MM_YY   :
  2746.       case DD_MM_YYYY :
  2747.          one = day;
  2748.          two = month;
  2749.          three = year;
  2750.          break;
  2751.       case YY_MM_DD   :
  2752.       case YYYY_MM_DD :
  2753.          one = year;
  2754.          two = month;
  2755.          three = day;
  2756.          break;
  2757.       case MM_DD_YY   :
  2758.       case MM_DD_YYYY :
  2759.       default         :
  2760.          one = month;
  2761.          two = day;
  2762.          three = year;
  2763.          break;
  2764.    }
  2765.    strcpy( dt, itoa( one, stuff, 10 ) );
  2766.    strcat( dt, "-" );
  2767.    strcat( dt, itoa( two, stuff, 10 ) );
  2768.    strcat( dt, "-" );
  2769.    strcat( dt, itoa( three, stuff, 10 ) );
  2770.  
  2771.    strcat( dt, "  " );
  2772.  
  2773.    pm = FALSE;
  2774.    if (mode.time_style == _12_HOUR) {
  2775.       if (hours >= 12 && hours < 24)
  2776.          pm = TRUE;
  2777.       if (hours < 1)
  2778.          hours = 12;
  2779.       else if (hours >= 13)
  2780.          hours -= 12;
  2781.    }
  2782.  
  2783.    if (hours < 1)
  2784.       strcat( dt, "0" );
  2785.    strcat( dt, itoa( hours, stuff, 10 ) );
  2786.    strcat( dt, ":" );
  2787.    if (minutes < 10)
  2788.       strcat( dt, "0" );
  2789.    strcat( dt, itoa( minutes, stuff, 10 ) );
  2790.    if (mode.time_style == _12_HOUR)
  2791.       strcat( dt, pm == FALSE ? "am" : "pm" );
  2792.    strcat( dt, "  " );
  2793.    return( add_chars( dt, window ) );
  2794. }
  2795.  
  2796.  
  2797. /*
  2798.  * Name:    add_chars
  2799.  * Purpose: insert string into file
  2800.  * Date:    June 5, 1992
  2801.  * Passed:  string:  string to add to file
  2802.  *          window:  pointer to current window
  2803.  */
  2804. int  add_chars( char *string, WINDOW *window )
  2805. {
  2806. int  rc = OK;
  2807.  
  2808.    while (*string) {
  2809.       g_status.key_pressed = *string;
  2810.       rc = insert_overwrite( window );
  2811.       ++string;
  2812.    }
  2813.    return( rc );
  2814. }
  2815.