home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional / OS2PRO194.ISO / os2 / com / utils / elm / sources / builtin.c < prev    next >
C/C++ Source or Header  |  1992-03-28  |  10KB  |  307 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: builtin.c,v 4.1 90/04/28 22:42:34 syd Exp $";
  3.  
  4. /*******************************************************************************
  5.  *  The Elm Mail System  -  $Revision: 4.1 $   $State: Exp $
  6.  *
  7.  *             Copyright (c) 1986, 1987 Dave Taylor
  8.  *             Copyright (c) 1988, 1989, 1990 USENET Community Trust
  9.  *******************************************************************************
  10.  * Bug reports, patches, comments, suggestions should be sent to:
  11.  *
  12.  *    Syd Weinstein, Elm Coordinator
  13.  *    elm@DSI.COM            dsinc!elm
  14.  *
  15.  *******************************************************************************
  16.  * $Log:    builtin.c,v $
  17.  * Revision 4.1  90/04/28  22:42:34  syd
  18.  * checkin of Elm 2.3 as of Release PL0
  19.  *
  20.  *
  21.  ******************************************************************************/
  22.  
  23. /** This is the built-in pager for displaying messages while in the Elm
  24.     program.  It's a bare-bones pager with precious few options. The idea
  25.     is that those systems that are sufficiently slow that using an external
  26.     pager such as 'more' is too slow, then they can use this!
  27.  
  28.     Also added support for the "builtin+" pager (clears the screen for
  29.     each new page) including a two-line overlap for context...
  30.  
  31. **/
  32.  
  33. #include "headers.h"
  34. #include <ctype.h>
  35.  
  36. #define  BEEP        007        /* ASCII Bell character */
  37.  
  38. static    unfilled_lines,
  39.     form_title;
  40.  
  41. int    lines_displayed,        /* total number of lines displayed      */
  42.     total_lines_to_display,        /* total number of lines in message     */
  43.     pages_displayed;         /* for the nth page titles and all      */
  44.  
  45. start_builtin(lines_in_message)
  46. int lines_in_message;
  47. {
  48.     /** clears the screen and resets the internal counters... **/
  49.  
  50.     dprint(8,(debugfile,
  51.         "displaying %d lines from message using internal pager\n",
  52.         lines_in_message));
  53.  
  54.     unfilled_lines = LINES;
  55.     form_title = 1;
  56.     lines_displayed = 0;
  57.         pages_displayed = 1;
  58.  
  59.     total_lines_to_display = lines_in_message;
  60. }
  61.  
  62. extern int tabspacing;
  63.  
  64. int
  65. next_line(inputptr, output, width)
  66. char **inputptr, *output;
  67. register unsigned width;
  68. {
  69.     /* Copy characters from input to output and copy
  70.      * remainder of output to output. In copying use ^X notation for
  71.      * control characters, '?' non-ascii characters, expand tabs
  72.      * to correct number of spaces till next tab stop.
  73.      * Column zero of the next line is considered to be the tab stop
  74.      * that follows the last one that fits on a line.
  75.      * Copy until newline/return encountered, null char encountered,
  76.      * width characters producted in output buffer.
  77.      * Formfeed is handled exceptionally. If encountered it
  78.      * is removed from input and 1 is returned. Otherwise 0 is returned.
  79.      */
  80.  
  81.     register char *optr, *iptr;
  82.     register unsigned chars_output, nt;
  83.     int ret_val;
  84.  
  85.     optr = output;
  86.     iptr = *inputptr;
  87.     chars_output = 0;
  88.  
  89.     ret_val = 0;    /* presume no formfeed */
  90.     while(1) {
  91.  
  92.       if(chars_output >= width) {        /* no more room on line */
  93.         *optr++ = '\n';
  94.         *optr++ = '\r';
  95.         /* if next input character is newline or return,
  96.          * we can skip over it since we are outputing a newline anyway */
  97.         if((*iptr == '\n') || (*iptr == '\r'))
  98.           iptr++;
  99.         break;
  100.       } else if (*iptr == '\n' || *iptr == '\r') {    /*newline or return */
  101.         *optr++ = '\r';
  102.         *optr++ = '\n';
  103.         iptr++;
  104.         break;            /* end of line */
  105.       } else if(*iptr == '\f') {        /* formfeed */
  106.         /* if next input character is newline or return,
  107.          * we can skip over it since we are outputing a formfeed anyway */
  108.         if((*++iptr == '\n') || (*iptr == '\r'))
  109.           iptr++;
  110.         ret_val = 1;
  111.         break;            /* leave rest of screen clear */
  112.       } else if(*iptr == '\0') {        /* none left in input string */
  113.         break;
  114.       } else if(*iptr == '\t') {        /* tab stop */
  115.         if((nt=next_tab(chars_output+1)) > width) {
  116. #ifndef OS2
  117.           *optr++ = '\r';        /* won't fit on this line - autowrap */
  118.           *optr++ = '\n';        /* tab by tabbing so-to-speak to 1st */
  119. #endif
  120.           iptr++;            /* column of next line */
  121.           break;
  122.         } else {        /* will fit - output proper num of spaces */
  123.           while(chars_output < nt-1) {
  124.         chars_output++;
  125.         *optr++ = ' ';
  126.           }
  127.           iptr++;
  128.         }
  129.       } else if(isprint(*iptr)) {
  130.         *optr++ = *iptr++;            /* printing character */
  131.         chars_output++;
  132.       } else {            /* non-white space control character */
  133.         if(chars_output + 2 <= width) {
  134.           *optr++ = '^';
  135.           *optr++ = (*iptr == '\177' ? '?' : (*iptr&0177) + 'A' - 1);
  136.           iptr++;
  137.           chars_output += 2;
  138.         } else {            /* no space on line for both chars */
  139.           break;
  140.         }
  141.       }
  142.     }
  143.     *optr = '\0';
  144.     *inputptr = iptr;
  145.     return(ret_val);
  146. }
  147.  
  148.  
  149. int
  150. display_line(input_line)
  151. char *input_line;
  152. {
  153.     /** Display the given line on the screen, taking into account such
  154.         dumbness as wraparound and such.  If displaying this would put
  155.         us at the end of the screen, put out the "MORE" prompt and wait
  156.         for some input.   Return non-zero if the user terminates the
  157.         paging (e.g. 'i') or zero if we should continue. Also,
  158.             this will pass back the value of any character the user types in
  159.         at the prompt instead, if needed... (e.g. if it can't deal with
  160.         it at this point)
  161.     **/
  162.  
  163.     char *pending, footer[SLEN], display_buffer[SLEN], ch;
  164.     int formfeed, lines_more;
  165.  
  166.         fixline(input_line);
  167.  
  168. #ifdef MMDF
  169.     if (strcmp(input_line, MSG_SEPERATOR) == 0)
  170.       strcpy(input_line," ");
  171. #endif /* MMDF */
  172.     pending = input_line;
  173.     CarriageReturn();
  174.  
  175.     do {
  176.  
  177.       /* while there is more space on the screen - leave prompt line free */
  178.       while(unfilled_lines > 0) {
  179.  
  180.         /* display a screen's lineful of the input line
  181.          * and reset pending to point to remainder of input line */
  182.         formfeed = next_line(&pending, display_buffer, COLUMNS);
  183.  
  184.         if(*display_buffer == '\0') {    /* no line to display */
  185.           if(!formfeed)    /* no "formfeed" to display
  186.                       * need more lines for screen */
  187.         return(FALSE);
  188.         } else
  189.           Write_to_screen(display_buffer, 0);
  190.  
  191.         /* if formfeed, clear remainder of screen */
  192.         if(formfeed) {
  193.           CleartoEOS();
  194.           unfilled_lines=0;
  195.         }
  196.         else
  197.           unfilled_lines--;
  198.  
  199.         /* if screen is not full (leave room for prompt)
  200.          * but we've used up input line, return */
  201.  
  202.         if(unfilled_lines > 0 && *pending == '\0')
  203.           return(FALSE);    /* we need more lines to fill screen */
  204.  
  205.         /* otherwise continue to display next part of input line */
  206.       }
  207.  
  208.       /* screen is now full - prompt for user input */
  209.       lines_more = total_lines_to_display - lines_displayed;
  210.       sprintf(footer,
  211.           ( (user_level == 0) ?
  212.   " There %s %d line%s left (%d%%). Press <space> for more, or 'i' to return. "
  213.           : (user_level == 1) ?
  214.   " %s%d line%s more (%d%%). Press <space> for more, 'i' to return. "
  215.           :
  216.   " %s%d line%s more (you've seen %d%%) "),
  217.            (user_level == 0 ?
  218.              (lines_more == 1 ? "is" : "are") : ""),
  219.            lines_more, plural(lines_more),
  220.            (int)((100L * lines_displayed) / total_lines_to_display));
  221.  
  222.       MoveCursor(LINES, 0);
  223.       StartBold();
  224.       Write_to_screen(footer, 0);
  225.       EndBold();
  226.  
  227.       switch(ch = ReadCh()) {
  228.  
  229.         case '\n':
  230.         case '\r':    /* scroll down a line */
  231.             unfilled_lines = 1;
  232.             ClearLine(LINES);
  233.             break;
  234.  
  235.         case ' ':    /* scroll a screenful */
  236.             unfilled_lines = LINES;
  237.             if(clear_pages) {
  238.               ClearScreen();
  239.               MoveCursor(0,0);
  240.               CarriageReturn();
  241.  
  242.               /* output title */
  243.               if(title_messages && filter) {
  244.                 title_for_page(++pages_displayed);
  245.                 unfilled_lines -= 2;
  246.               }
  247.             } else ClearLine(LINES);
  248.  
  249.             /* and keep last line to be first line of next
  250.              * screenful unless we had a formfeed */
  251.             if(!formfeed) {
  252.               if(clear_pages)
  253.                 Write_to_screen(display_buffer, 0);
  254.               unfilled_lines--;
  255.             }
  256.             break;
  257.  
  258.         default:    return(ch);
  259.       }
  260.       CarriageReturn();
  261.     } while(*pending);
  262.     return(FALSE);
  263. }
  264.  
  265. title_for_page(page)
  266. int page;
  267. {
  268.     /** Output a nice title for the second thru last pages of the message
  269.         we're currently reading. Note - this code is very similar to
  270.         that which produces the title for the first page, except that
  271.         page number replaces the date and the method by which it
  272.         gets to the screen **/
  273.  
  274.     static char title1[SLEN], title2[SLEN];
  275.     char titlebuf[SLEN], title3[SLEN], who[SLEN];
  276.     static t1_len, t2_len;
  277.     register int padding, showing_to;
  278.  
  279.     /* format those parts of the title that are constant for a message */
  280.     if(form_title) {
  281.  
  282.       showing_to = tail_of(headers[current-1]->from, who,
  283.         headers[current-1]->to);
  284.  
  285.       sprintf(title1, "%s %d/%d  ",
  286.           headers[current-1]->status & DELETED ? "[deleted]" :
  287.           headers[current-1]->status & FORM_LETTER ? "Form": "Message",
  288.           current, message_count);
  289.       t1_len = strlen(title1);
  290.       sprintf(title2, "%s %s", showing_to? "To" : "From", who);
  291.       t2_len = strlen(title2);
  292.     }
  293.     /* format those parts of the title that vary between pages of a mesg */
  294.     sprintf(title3, "  Page %d", page);
  295.  
  296.     /* truncate or pad title2 portion on the right
  297.      * so that line fits exactly to the rightmost column */
  298.     padding = COLUMNS - 1 - (t1_len + t2_len + strlen(title3));
  299.  
  300.     sprintf(titlebuf, "%s%-*.*s%s\n\r\n\r", title1, t2_len+padding,
  301.         t2_len+padding, title2, title3);
  302.         /* extra newline is to give a blank line after title */
  303.  
  304.     Write_to_screen(titlebuf, 0);
  305.     form_title = 0;
  306. }
  307.