home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / elm / elm2.4 / src / wordwrap.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-11  |  9.7 KB  |  358 lines

  1. /*******************************************************************************
  2.  *  The Elm Mail System  -  $Revision: 5.4 $   $State: Exp $
  3.  *
  4.  *            Copyright (c) 1988-1992 USENET Community Trust
  5.  *            Copyright (c) 1986,1987 Dave Taylor
  6.  *******************************************************************************
  7.  * Bug reports, patches, comments, suggestions should be sent to:
  8.  *
  9.  *    Syd Weinstein, Elm Coordinator
  10.  *    elm@DSI.COM            dsinc!elm
  11.  *
  12.  *******************************************************************************
  13.  * $Log: wordwrap.c,v $
  14.  * Revision 5.4  1993/04/12  03:02:40  syd
  15.  * Check for EINTR if getchar() returns EOF. Happens after a resume from an
  16.  * interactive stop.
  17.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  18.  *
  19.  * Revision 5.3  1993/04/12  02:43:53  syd
  20.  * The builtin editor couldn't back up to a line that had a character
  21.  * at the wrapcolumn position.
  22.  * Added tab handling to the builtin editor.
  23.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  24.  *
  25.  * Revision 5.2  1993/02/03  16:45:26  syd
  26.  * A Raw(OFF) was missing so when in mail only mode and one
  27.  * does f)orget, the "Message saved" ends up on wrong screen.
  28.  * Also added \r\n to end of messages to make output look nicer.
  29.  *
  30.  * When composing mail in the builtin editor, it wrapped on /.
  31.  * From: Jan Djarv <Jan.Djarv@sa.erisoft.se>
  32.  *
  33.  * Revision 5.1  1992/10/03  22:58:40  syd
  34.  * Initial checkin as of 2.4 Release at PL0
  35.  *
  36.  *
  37.  ******************************************************************************/
  38.  
  39. /***  Routines to wrap lines when using the "builtin" editor
  40.  
  41. ***/
  42.  
  43. #include "headers.h"
  44. #include <errno.h>
  45. #include <ctype.h>
  46.  
  47. #ifdef BSD
  48. #  undef tolower
  49. #endif
  50.  
  51. extern int errno;        /* system error number */
  52.  
  53. unsigned alarm();
  54.  
  55. #define isstopchar(c)        (c == ' ' || c == '\t')
  56. #define isslash(c)        (c == '/')
  57. #define erase_a_char()        { Writechar(BACKSPACE); Writechar(' '); \
  58.                       Writechar(BACKSPACE); fflush(stdout); }
  59.  
  60.     /* WARNING: this macro destroys nr */
  61. #define erase_tab(nr)        do Writechar(BACKSPACE); while (--(nr) > 0)
  62.  
  63. int
  64. wrapped_enter(string, tail, x, y, edit_fd, append_current)
  65. char *string, *tail;
  66. int  x,y, *append_current;
  67. FILE *edit_fd;
  68.  
  69. {
  70.     /** This will display the string on the screen and allow the user to
  71.         either accept it (by pressing RETURN) or alter it according to
  72.         what the user types.   The various flags are:
  73.              string    is the buffer to use (with optional initial value)
  74.          tail       contains the portion of input to be wrapped to the
  75.                next line
  76.           x,y       is the location we're at on the screen (-1,-1 means
  77.                that we can't use this info and need to find out
  78.                the current location)
  79.          append_current  means that we have an initial string and that
  80.                the cursor should be placed at the END of the line,
  81.                not the beginning (the default).
  82.           
  83.         If we hit an interrupt or EOF we'll return non-zero.
  84.     **/
  85.  
  86.     int ch, wrapcolumn = 70, iindex = 0;
  87.     int addon = 0;    /* Space added by tabs. iindex+addon == column */
  88.     int tindex = 0;    /* Index to the tabs array. */
  89.     int tabs[10];    /* Spaces each tab adds. size <= wrapcolumn/8+1 */
  90.     register int ch_count = 0, escaped = OFF;
  91.     long newpos, pos;
  92.     char line[SLEN];
  93.  
  94.     clearerr(stdin);
  95.  
  96.     if(!(x >=0 && y >= 0))
  97.       GetXYLocation(&x, &y);
  98.     PutLine1(x, y, "%s", string);    
  99.  
  100.     CleartoEOLN();
  101.  
  102.     if (! *append_current) {
  103.       MoveCursor(x,y);
  104.     }
  105.     else
  106.       iindex = strlen(string);
  107.  
  108.     if (cursor_control)
  109.       transmit_functions(OFF);
  110.  
  111.     /** now we have the screen as we want it and the cursor in the 
  112.         right place, we can loop around on the input and return the
  113.         string as soon as the user presses <RETURN> or the line wraps.
  114.     **/
  115.  
  116.     do {
  117.       ch = getchar();
  118.  
  119.       if (ch == EOF && ferror(stdin) && errno == EINTR) {
  120.         clearerr(stdin);
  121.         continue;
  122.       }
  123.  
  124.       if (ch == ctrl('D') || ch == EOF) {        /* we've hit EOF */
  125.         if (cursor_control)
  126.           transmit_functions(ON);
  127.         *append_current = 0;
  128.         return(1);
  129.       }
  130.  
  131.       if (ch_count++ == 0) {
  132.         if (ch == '\n' || ch == '\r') {
  133.           if (cursor_control)
  134.             transmit_functions(ON);
  135.           *append_current = 0;
  136.           return(0);
  137.         }
  138.         else if (! *append_current) {
  139.           CleartoEOLN();
  140.           iindex = (*append_current? strlen(string) : 0);
  141.         }
  142.       }
  143.  
  144.       /* the following is converted from a case statement to
  145.          allow the variable characters (backspace, kill_line
  146.          and break) to be processed.  Case statements in
  147.          C require constants as labels, so it failed ...
  148.       */
  149.  
  150.       if (ch == backspace) {
  151.         escaped = OFF;
  152.         if (iindex > 0) {
  153.             iindex--;
  154.           if (string[iindex] == '\t') {
  155.         addon -= tabs[--tindex] - 1;
  156.         erase_tab(tabs[tindex]);
  157.           } else erase_a_char();
  158.  
  159. #ifdef FTRUNCATE
  160.  
  161.         } else { /** backspace to end of previous line **/
  162.  
  163.           fflush(edit_fd);
  164.           if ((pos = ftell(edit_fd)) <= 0L) { /** no previous line **/
  165.         Writechar('\007');
  166.  
  167.           } else {
  168.  
  169.         /** get the last 256 bytes written **/
  170.         if ((newpos = pos - 256L) <= 0L) newpos = 0;
  171.         (void) fseek(edit_fd, newpos, 0L);
  172.         (void) fread(line, sizeof(*line), (int) (pos-newpos),
  173.                      edit_fd);
  174.         pos--;
  175.  
  176.         /** the last char in line should be '\n'
  177.             change it to null **/
  178.         if (line[(int) (pos-newpos)] == '\n')
  179.           line[(int) (pos-newpos)] = '\0';
  180.  
  181.         /** find the end of the previous line ('\n') **/
  182.         for (pos--; pos > newpos && line[(int) (pos-newpos)] != '\n';
  183.             pos--);
  184.         /** check to see if this was the first line in the file **/
  185.         if (line[(int) (pos-newpos)] == '\n') /** no - it wasn't **/
  186.           pos++;
  187.         (void) strcpy(string, &line[(int) (pos-newpos)]);
  188.         line[(int) (pos-newpos)] = '\0';
  189.  
  190.         /** truncate the file to the current position
  191.             THIS WILL NOT WORK ON SYS-V **/
  192.         (void) fseek(edit_fd, newpos, 0L);
  193.         (void) fputs(line, edit_fd);
  194.         fflush(edit_fd);
  195.         (void) ftruncate(fileno(edit_fd), (int) ftell(edit_fd));
  196.         (void) fseek(edit_fd, ftell(edit_fd), 0L);
  197.  
  198.         /** rewrite line on screen and continue working **/
  199.         GetXYLocation(&x, &y);
  200.         if (x > 0) x--;
  201.         PutLine1(x, y, "%s", string);
  202.         CleartoEOLN();
  203.         iindex = strlen(string);
  204.  
  205.         /* Reload tab positions */
  206.         addon = tindex = 0;
  207.         for (pos = 0; pos < iindex; pos++)
  208.           if (string[pos] == '\t')
  209.             addon += (tabs[tindex++] = 8 - ((pos+addon) & 07)) - 1;
  210.           }
  211.  
  212. #endif
  213.  
  214.         }
  215.         fflush(stdout);
  216.       }
  217.       else if (ch == EOF || ch == '\n' || ch == '\r') {
  218.         escaped = OFF;
  219.         string[iindex] = '\0';
  220.         if (cursor_control)
  221.           transmit_functions(ON);
  222.         *append_current = 0;
  223.         return(0);
  224.       }
  225.       else if (ch == ctrl('W')) {    /* back up a word! */
  226.         escaped = OFF;
  227.         if (iindex == 0)
  228.           continue;        /* no point staying here.. */
  229.         iindex--;
  230.         if (isslash(string[iindex])) {
  231.           erase_a_char();
  232.         }
  233.         else {
  234.           while (iindex >= 0 && isspace(string[iindex])) {
  235.         if (string[iindex] == '\t') {
  236.           addon -= tabs[--tindex] - 1;
  237.           erase_tab(tabs[tindex]);
  238.         } else erase_a_char();
  239.             iindex--;
  240.           }
  241.  
  242.           while (iindex >= 0 && ! isstopchar(string[iindex])) {
  243.             iindex--;
  244.             erase_a_char();
  245.           }
  246.           iindex++;    /* and make sure we point at the first AVAILABLE slot */
  247.         }
  248.       }
  249.       else if (ch == ctrl('R')) {
  250.         escaped = OFF;
  251.         string[iindex] = '\0';
  252.         PutLine1(x,y, "%s", string);    
  253.         CleartoEOLN();
  254.       }
  255.       else if (!escaped && ch == kill_line) {
  256.         /* needed to test if escaped since kill_line character could
  257.          * be a desired valid printing character */
  258.         escaped = OFF;
  259.         MoveCursor(x,y);
  260.         CleartoEOLN();
  261.         iindex = 0;
  262.       }
  263.       else if (ch == '\0') {
  264.         escaped = OFF;
  265.         if (cursor_control)
  266.           transmit_functions(ON);
  267.         fflush(stdin);     /* remove extraneous chars, if any */
  268.         string[0] = '\0'; /* clean up string, and... */
  269.         *append_current = 0;
  270.         return(-1);
  271.       }
  272.       else if (!isprint(ch) && ch != '\t') {
  273.         /* non-printing character - warn with bell*/
  274.         /* don't turn off escaping backslash since current character
  275.          * doesn't "use it up".
  276.          */
  277.         Writechar('\007');
  278.       }
  279.       else {  /* default case */
  280.           if(escaped && (ch == backspace || ch == kill_line)) {
  281.         /* if last character was a backslash,
  282.          * and if this character is escapable
  283.          * simply write this character over it even if
  284.          * this character is a backslash.
  285.          */
  286.         Writechar(BACKSPACE);
  287.         iindex--;
  288.         string[iindex++] = ch;
  289.         Writechar(ch);
  290.             escaped = OFF;
  291.           } else {
  292.         if (ch == '\t')
  293.           addon += (tabs[tindex++] = 8 - ((addon+iindex) & 07)) - 1;
  294.  
  295.         string[iindex++] = ch;
  296.         Writechar(ch);
  297.         escaped = ( ch == '\\' ? ON : OFF);
  298.           }
  299.       }
  300.     } while (iindex+addon < wrapcolumn);
  301.  
  302.     string[iindex] = '\0';
  303.     *append_current = line_wrap(string,tail,&iindex,&tabs[tindex-1]);
  304.  
  305.     if (cursor_control)
  306.       transmit_functions(ON);
  307.     return(0);
  308. }
  309.  
  310. int
  311. line_wrap(string,tail,count,tabs)
  312. char *string;    /* The string to be wrapped */
  313. char *tail;    /* The part of the string which is wrapped */
  314. int *count;    /* Offset of string terminator */
  315. int *tabs;    /* List of how many spaces each tab adds */
  316. {
  317.     /** This will check for line wrap.  If the line was wrapped,
  318.         it will back up to white space (if possible), write the
  319.         shortened line, and put the remainder at the beginning
  320.         of the string.  Returns 1 if wrapped, 0 if not.
  321.     **/
  322.  
  323.     int n = *count;
  324.     int i, j;
  325.  
  326.     /* Look for a space */
  327.     while (n && !isstopchar(string[n]))
  328.       --n;
  329.  
  330.     /* If break found */
  331.     if (n) {
  332.  
  333.       /* Copy part to be wrapped */
  334.       for (i=0,j=n+1;j<=*count;tail[i++]=string[j++]);
  335.  
  336.       /* Skip the break character and any whitespace */
  337.       while (n && isstopchar(string[n]))
  338.         --n;
  339.  
  340.       if (n) n++; /* Move back into the whitespace */
  341.     }
  342.  
  343.     /* If no break found */
  344.     if (!n) {
  345.       (*count)--;
  346.       strcpy(tail, &string[*count]);
  347.       erase_a_char();
  348.     } else /* Erase the stuff that will wrap */
  349.       while (*count > n) {
  350.         --(*count);
  351.       if (string[*count] == '\t') erase_tab(*tabs--);
  352.       else erase_a_char();
  353.       }
  354.  
  355.     string[*count] = '\0';
  356.     return(1);
  357. }
  358.