home *** CD-ROM | disk | FTP | other *** search
/ Best Objectech Shareware Selections / UNTITLED.iso / boss / word / text / 024 / tab.c < prev    next >
C/C++ Source or Header  |  1993-06-04  |  27KB  |  953 lines

  1. /*
  2.  * Most of the tab routines were gathered into one file.  There is an
  3.  * assembly routine tdeasm.c that expands tabs.  That routine is in
  4.  * assembly to keep screen updates fairly fast.
  5.  *
  6.  * The basic detab and entab algorithms were supplied by Dave Regan,
  7.  *   regan@jacobs.cs.orst.edu
  8.  *
  9.  * For more info on tabs see:
  10.  *
  11.  *     Brian W. Kernighan and P. J. Plauger, _Software Tools_, Addison-
  12.  *     Wesley Publishing Company, Reading, Mass, 1976, pp 18-27 and 35-39,
  13.  *     ISBN 0-20103669-X.
  14.  *
  15.  * The above reference gives info on fixed and variable tabs.  But when
  16.  *  it comes to non-fixed tabs, I prefer "smart" tabs.  Being lazy, I find
  17.  *  it more convenient to let the editor figure variable tabs for me.
  18.  *
  19.  *
  20.  * New editor name:  TDE, the Thomson-Davis Editor.
  21.  * Author:           Frank Davis
  22.  * Date:             June 5, 1991, version 1.0
  23.  * Date:             July 29, 1991, version 1.1
  24.  * Date:             October 5, 1991, version 1.2
  25.  * Date:             January 20, 1992, version 1.3
  26.  * Date:             February 17, 1992, version 1.4
  27.  * Date:             April 1, 1992, version 1.5
  28.  * Date:             June 5, 1992, version 2.0
  29.  * Date:             October 31, 1992, version 2.1
  30.  * Date:             April 1, 1993, version 2.2
  31.  * Date:             June 5, 1993, version 3.0
  32.  *
  33.  * This program is released into the public domain, Frank Davis.
  34.  *   You may distribute it freely.
  35.  */
  36.  
  37. #include "tdestr.h"
  38. #include "common.h"
  39. #include "tdefunc.h"
  40. #include "define.h"
  41.  
  42.  
  43. /*
  44.  * Name:    tab_key
  45.  * Purpose: To make the necessary changes after the user types the tab key.
  46.  * Date:    June 5, 1991
  47.  * Passed:  window:  pointer to current window
  48.  * Notes:   If in insert mode, then this function adds the required
  49.  *           number of spaces in the file.
  50.  *          If not in insert mode, then tab simply moves the cursor right
  51.  *           the required distance.
  52.  */
  53. int  tab_key( WINDOW *window )
  54. {
  55. int  spaces;    /* the spaces to move to the next tab stop */
  56. char *source;   /* source for block move to make room for c */
  57. char *dest;     /* destination for block move */
  58. int  pad;
  59. int  len;
  60. register int rcol;
  61. int  old_bcol;
  62. register WINDOW *win;   /* put window pointer in a register */
  63. int  rc;
  64.  
  65.    win  = window;
  66.    if (win->ll->len  ==  EOF)
  67.       return( OK );
  68.    rcol = win->rcol;
  69.    old_bcol = win->bcol;
  70.    show_ruler_char( win );
  71.    /*
  72.     * work out the number of spaces to the next tab stop
  73.     */
  74.    if (mode.smart_tab)
  75.       spaces = next_smart_tab( win );
  76.    else
  77.       spaces = mode.ltab_size - (rcol % mode.ltab_size);
  78.  
  79.    assert( spaces >= 0 );
  80.    assert( spaces < MAX_LINE_LENGTH );
  81.  
  82.    rc = OK;
  83.    if (mode.insert && rcol + spaces < g_display.line_length) {
  84.       copy_line( win->ll );
  85.       detab_linebuff( );
  86.  
  87.       /*
  88.        * work out how many characters need to be inserted
  89.        */
  90.       len = g_status.line_buff_len;
  91.       pad = rcol > len ? rcol - len : 0;
  92.       if (len + pad + spaces >= g_display.line_length) {
  93.          /*
  94.           *  line too long to add
  95.           */
  96.          error( WARNING, win->bottom_line, ed1 );
  97.          rc = ERROR;
  98.          g_status.copied = FALSE;
  99.       } else {
  100.          if (pad > 0  || spaces > 0) {
  101.             source = g_status.line_buff + rcol - pad;
  102.             dest = source + pad + spaces;
  103.  
  104.             assert( len + pad - rcol >= 0 );
  105.             assert( len + pad - rcol < MAX_LINE_LENGTH );
  106.  
  107.             memmove( dest, source, len + pad - rcol );
  108.  
  109.             /*
  110.              * if padding was required, then put in the required spaces
  111.              */
  112.  
  113.             assert( pad + spaces >= 0 );
  114.             assert( pad + spaces < MAX_LINE_LENGTH );
  115.  
  116.             memset( source, ' ', pad + spaces );
  117.             g_status.line_buff_len += pad + spaces;
  118.             entab_linebuff( );
  119.          }
  120.  
  121.          win->ll->dirty = TRUE;
  122.          win->file_info->dirty = GLOBAL;
  123.          show_changed_line( win );
  124.          rcol += spaces;
  125.          win->ccol += spaces;
  126.       }
  127.    } else if (rcol + spaces <= g_display.line_length) {
  128.       /*
  129.        * advance the cursor without changing the text underneath
  130.        */
  131.       rcol += spaces;
  132.       win->ccol += spaces;
  133.    }
  134.    check_virtual_col( win, rcol, win->ccol );
  135.    if (old_bcol != win->bcol) {
  136.       make_ruler( win );
  137.       show_ruler( win );
  138.    }
  139.    return( rc );
  140. }
  141.  
  142.  
  143. /*
  144.  * Name:    backtab
  145.  * Purpose: To make the necessary changes after the user presses the backtab.
  146.  * Date:    November 1, 1991
  147.  * Passed:  window:  pointer to current window
  148.  * Notes:   If in insert mode, then this function subs the required
  149.  *           number of spaces in the file.
  150.  *          If not in insert mode, then tab simply moves the cursor left
  151.  *           the required distance.
  152.  */
  153. int  backtab( WINDOW *window )
  154. {
  155. int  spaces;    /* the spaces to move to the next tab stop */
  156. char *source;   /* source for block move to make room for c */
  157. char *dest;     /* destination for block move */
  158. int  pad;
  159. int  len;
  160. register int rcol;
  161. int  old_bcol;
  162. register WINDOW *win;   /* put window pointer in a register */
  163.  
  164.    win  = window;
  165.    rcol = win->rcol;
  166.    if (win->ll->len == EOF || win->rcol == 0)
  167.       return( OK );
  168.    old_bcol = win->bcol;
  169.    show_ruler_char( win );
  170.  
  171.    /*
  172.     * work out the number of spaces to the previous tab stop
  173.     */
  174.    if (mode.smart_tab)
  175.       spaces = prev_smart_tab( win );
  176.    else
  177.       spaces = win->rcol % mode.ltab_size;
  178.  
  179.    if (spaces == 0)
  180.       spaces = mode.ltab_size;
  181.    copy_line( win->ll );
  182.    detab_linebuff( );
  183.    len = g_status.line_buff_len;
  184.    if (mode.insert && rcol - spaces < len) {
  185.       pad = rcol > len ? rcol - len : 0;
  186.       if (pad > 0  || spaces > 0) {
  187.          /*
  188.           * if padding was required, then put in the required spaces
  189.           */
  190.          if (pad > 0) {
  191.  
  192.             assert( rcol - pad >= 0 );
  193.             assert( pad < MAX_LINE_LENGTH );
  194.  
  195.             source = g_status.line_buff + rcol - pad;
  196.             dest = source + pad;
  197.  
  198.             assert( pad >= 0 );
  199.             assert( pad < MAX_LINE_LENGTH );
  200.  
  201.             memmove( dest, source, pad );
  202.             memset( source, ' ', pad );
  203.             g_status.line_buff_len += pad;
  204.          }
  205.          source = g_status.line_buff + rcol;
  206.          dest = source - spaces;
  207.  
  208.          assert( len + pad - rcol >= 0 );
  209.          assert( len + pad - rcol < MAX_LINE_LENGTH );
  210.  
  211.          memmove( dest, source, len + pad - rcol );
  212.          g_status.line_buff_len -= spaces;
  213.          entab_linebuff( );
  214.       }
  215.  
  216.       win->ll->dirty = TRUE;
  217.       win->file_info->dirty = GLOBAL;
  218.       show_changed_line( win );
  219.       rcol -= spaces;
  220.       win->ccol -= spaces;
  221.    } else {
  222.       /*
  223.        * move the cursor without changing the text underneath
  224.        */
  225.       rcol -= spaces;
  226.       if (rcol < 0)
  227.          rcol = 0;
  228.       win->ccol -= spaces;
  229.    }
  230.    check_virtual_col( win, rcol, win->ccol );
  231.    if (old_bcol != win->bcol) {
  232.       make_ruler( win );
  233.       show_ruler( win );
  234.    }
  235.    return( OK );
  236. }
  237.  
  238.  
  239. /*
  240.  * Name:    next_smart_tab
  241.  * Purpose: To find next smart tab
  242.  * Date:    June 5, 1992
  243.  * Passed:  window: pointer to the current window
  244.  * Notes:   To find a smart tab 1) find the first non-blank line above the
  245.  *            current line, 2) find the first non-blank character after
  246.  *            column of the cursor.
  247.  */
  248. int  next_smart_tab( WINDOW *window )
  249. {
  250. register int spaces;    /* the spaces to move to the next tab stop */
  251. text_ptr s;             /* pointer to text */
  252. line_list_ptr ll;
  253. register WINDOW *win;   /* put window pointer in a register */
  254. int  len;
  255.  
  256.    /*
  257.     * find first previous non-blank line above the cursor.
  258.     */
  259.    win = window;
  260.    ll = win->ll->prev;
  261.    while (ll != NULL  && is_line_blank( ll->line, ll->len ))
  262.       ll = ll->prev;
  263.  
  264.    if (ll != NULL) {
  265.       s = ll->line;
  266.       /*
  267.        * if cursor is past the eol of the smart line, lets find the
  268.        *   next fixed tab.
  269.        */
  270.       if (window->rcol >= find_end( s, ll->len ))
  271.          spaces =