home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / APPS / elm.lzh / ELM / SRC / IN_UTILS.C < prev    next >
Text File  |  1991-01-11  |  13KB  |  508 lines

  1.  
  2. static char rcsid[] = "@(#)$Id: in_utils.c,v 4.1 90/04/28 22:43:13 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:    in_utils.c,v $
  17.  * Revision 4.1  90/04/28  22:43:13  syd
  18.  * checkin of Elm 2.3 as of Release PL0
  19.  * 
  20.  *
  21.  ******************************************************************************/
  22.  
  23. /** Mindless I/O routines for ELM 
  24.     
  25. **/
  26.  
  27. #include "headers.h"
  28. #include <errno.h>
  29. #include <ctype.h>
  30.  
  31. #ifdef BSD
  32. #  undef tolower
  33. #endif
  34.  
  35. extern int errno;        /* system error number */
  36.  
  37. unsigned alarm();
  38.  
  39. #define isstopchar(c)        (c == ' ' || c == '\t' || c == '/')
  40. #define isslash(c)        (c == '/')
  41. #define erase_a_char()        { Writechar(BACKSPACE); Writechar(' '); \
  42.                       Writechar(BACKSPACE); fflush(stdout); }
  43.  
  44. int
  45. want_to(question, dflt)
  46. char *question, dflt;
  47. {
  48.     /** Ask 'question' on LINES-2 left enough to just leave room for an
  49.         answer, returning the answer in lower case.
  50.         Echo answer as full "Yes" or "No".  'dflt' is the 
  51.         default answer if <return> is pressed. (Note: 'dflt' is also what 
  52.         will be returned if <return> is pressed!)
  53.     **/
  54.     register int ch, cols;
  55.  
  56.     cols = COLUMNS - (strlen(question) + 5 );    /* 5 for "Yes." + 1 */
  57.  
  58.     MoveCursor(LINES-3, cols);
  59.     CleartoEOLN();
  60.     PutLine3(LINES-3, cols,"%s%c%c", question, dflt, BACKSPACE);
  61.     fflush(stdout);
  62.     fflush(stdin);
  63.  
  64.     ch = ReadCh();
  65.     ch = tolower(ch);
  66.  
  67.     while (!( ch == 'y' || ch == 'n' || ch == '\l' || ch == '\r')) {
  68.       ch = ReadCh();
  69.       ch = tolower(ch);
  70.     }
  71.     if(ch == '\l' || ch == '\r')
  72.       ch = dflt;
  73.  
  74.     if(ch == 'y')
  75.       Write_to_screen("Yes.", 0);
  76.     else
  77.       Write_to_screen("No.", 0);
  78.  
  79.     return(ch);
  80. }
  81.  
  82. int
  83. read_number(ch)
  84. char ch;
  85. {
  86.     /** Read a number, where 'ch' is the leading digit! **/
  87.     
  88.     char buff[NLEN];
  89.     int  num;
  90.  
  91.     buff[0] = ch;
  92.     buff[1] = '\0';
  93.  
  94.     PutLine0(LINES-3, COLUMNS-40,"Set current message to :");
  95.     if (optionally_enter(buff, LINES-3, COLUMNS-15, TRUE, FALSE) == -1)
  96.       return(current);
  97.  
  98.     sscanf(buff,"%d", &num);
  99.     return(num);
  100. }
  101.  
  102. int
  103. optionally_enter(string, x, y, append_current, passwd)
  104. char *string;
  105. int  x,y, append_current, passwd;
  106. {
  107.     /** This will display the string on the screen and allow the user to
  108.         either accept it (by pressing RETURN) or alter it according to
  109.         what the user types.   The various flags are:
  110.              string    is the buffer to use (with optional initial value)
  111.           x,y       is the location we're at on the screen (-1,-1 means
  112.                that we can't use this info and need to find out
  113.                the current location)
  114.          append_current  means that we have an initial string and that
  115.                the cursor should be placed at the END of the line,
  116.                not the beginning (the default).
  117.          passwd       accept non-printing characters and do not echo
  118.                entered characters.
  119.           
  120.         If we hit an interrupt or EOF we'll return non-zero.
  121.     **/
  122.  
  123.     int ch;
  124.     register int ch_count = 0, iindex = 0, escaped = OFF;
  125.  
  126.     clearerr(stdin);
  127.  
  128.     if(!passwd) {
  129.       if(!(x >=0 && y >= 0))
  130.         GetXYLocation(&x, &y);
  131.       PutLine1(x, y, "%s", string);    
  132.     }
  133.  
  134.     CleartoEOLN();
  135.  
  136.     if (! append_current) {
  137.       MoveCursor(x,y);
  138.     }
  139.     else
  140.       iindex = strlen(string);
  141.  
  142.     if (cursor_control)
  143.       transmit_functions(OFF);
  144.  
  145.     /** now we have the screen as we want it and the cursor in the 
  146.         right place, we can loop around on the input and return the
  147.         string as soon as the user presses <RETURN>
  148.     **/
  149.  
  150.     do {
  151.       ch = ReadCh();    /* getchar(); */
  152.       
  153.       if (ch == ctrl('D') || ch == EOF) {        /* we've hit EOF */
  154.         if (cursor_control)
  155.           transmit_functions(ON);
  156.         return(1);
  157.       }
  158.  
  159.       if (ch_count++ == 0) {
  160.         if (ch == '\l' || ch == '\r') {
  161.           if (cursor_control)
  162.             transmit_functions(ON);
  163.           return(0);
  164.         }
  165.         else if (! append_current) {
  166.           CleartoEOLN();
  167.           iindex = (append_current? strlen(string) : 0);
  168.         }
  169.       }
  170.  
  171.       /* the following is converted from a case statement to
  172.          allow the variable characters (backspace, kill_line
  173.          and break) to be processed.  Case statements in
  174.          C require constants as labels, so it failed ...
  175.       */
  176.  
  177.       if (ch == backspace &&
  178.         (!escaped || (!isprint(ch) && !passwd))) {
  179.         /* This is tricky. Here we are dealing with all situations
  180.          * under which a backspace (really whatever erase char is
  181.          * set to, not necessarily \b) erases the previous character.
  182.          * It will erase unless escaped, because if it's escaped
  183.          * it is taken literally. There is one exception to that --
  184.          * if backspace would be rejected (we don't accept non-printing
  185.          * characters in non-passwd mode), we accept it here as an
  186.          * erasing character, for it if got rejected there would
  187.          * be no way of erasing a preceding backslash. */
  188.         escaped = OFF;
  189.         if (iindex > 0) {
  190.           if(!passwd)
  191.         Writechar(BACKSPACE);
  192.             iindex--;
  193.         }
  194.         if(!passwd) {
  195.           Writechar(' ');
  196.           Writechar(BACKSPACE);
  197.           fflush(stdout);
  198.         }
  199.       }
  200.       else if (ch == EOF || ch == '\l' || ch == '\r') {
  201.         escaped = OFF;
  202.         string[iindex] = '\0';
  203.         if (cursor_control)
  204.           transmit_functions(ON);
  205.         return(0);
  206.       }
  207.       else if (!passwd && ch == ctrl('W')) {    /* back up a word! */
  208.         escaped = OFF;
  209.         if (iindex == 0)
  210.           continue;        /* no point staying here.. */
  211.         iindex--;
  212.         if (isslash(string[iindex])) {
  213.           erase_a_char();
  214.         }
  215.         else {
  216.           while (iindex >= 0 && isspace(string[iindex])) {
  217.             iindex--;
  218.             erase_a_char();
  219.           }
  220.  
  221.           while (iindex >= 0 && ! isstopchar(string[iindex])) {
  222.             iindex--;
  223.             erase_a_char();
  224.           }
  225.           iindex++;    /* and make sure we point at the first AVAILABLE slot */
  226.         }
  227.       }
  228.       else if (!passwd && ch == ctrl('R')) {
  229.         escaped = OFF;
  230.         string[iindex] = '\0';
  231.         PutLine1(x,y, "%s", string);    
  232.         CleartoEOLN();
  233.       }
  234.       else if (!escaped && ch == kill_line) {
  235.         /* needed to test if escaped since kill_line character could
  236.          * be a desired valid printing character */
  237.         escaped = OFF;
  238.         if(!passwd) {
  239.           MoveCursor(x,y);
  240.           CleartoEOLN();
  241.         }
  242.         iindex = 0;
  243.       }
  244.       else if (ch == '\0') {
  245.         escaped = OFF;
  246.         if (cursor_control)
  247.           transmit_functions(ON);
  248.         fflush(stdin);     /* remove extraneous chars, if any */
  249.         string[0] = '\0'; /* clean up string, and... */
  250.         return(-1);
  251.       }
  252.       else if (!passwd && !isprint(ch)) {
  253.         /* non-printing character - warn with bell*/
  254.         /* don't turn off escaping backslash since current character
  255.          * doesn't "use it up".
  256.          */
  257.         Writechar('\007');
  258.       }
  259.       else {  /* default case */
  260.           if(escaped && (ch == backspace || ch == kill_line)) {
  261.         /* if last character was a backslash,
  262.          * and if this character is escapable
  263.          * simply write this character over it even if
  264.          * this character is a backslash.
  265.          */
  266.         if(!passwd)
  267.           Writechar(BACKSPACE);
  268.         iindex--;
  269.         string[iindex++] = ch;
  270.         if(!passwd)
  271.           Writechar(ch);
  272.             escaped = OFF;
  273.           } else {
  274.         string[iindex++] = ch;
  275.         if(!passwd)
  276.           Writechar(ch);
  277.         escaped = ( ch == '\\' ? ON : OFF);
  278.           }
  279.       }
  280.     } while (iindex < SLEN);
  281.  
  282.     string[iindex] = '\0';
  283.  
  284.     if (cursor_control)
  285.       transmit_functions(ON);
  286.  
  287.     return(0);
  288. }
  289.  
  290. int
  291. pattern_enter(string, alt_string, x, y, alternate_prompt)
  292. char *string, *alt_string, *alternate_prompt;
  293. int  x,y;
  294. {
  295.     /** This function is functionally similar to the routine
  296.         optionally-enter, but if the first character pressed
  297.         is a '/' character, then the alternate prompt and string
  298.         are used rather than the normal one.  This routine 
  299.         returns 1 if alternate was used, 0 if not
  300.     **/
  301.  
  302.     int ch;
  303.     register iindex = 0, escaped = OFF;
  304.  
  305.     PutLine1(x, y, "%s", string);    
  306.     CleartoEOLN();
  307.     MoveCursor(x,y);
  308.  
  309.     if (cursor_control)
  310.       transmit_functions(OFF);
  311.  
  312. /*    ch = getchar();        */
  313.     ch = ReadCh();
  314.  
  315.     if (ch == '\l' || ch == '\r') {
  316.       if (cursor_control)
  317.         transmit_functions(ON);
  318.       return(0);    /* we're done.  No change needed */
  319.     }
  320.     
  321.     if (ch == '/') {
  322.       PutLine1(x, 0, "%s", alternate_prompt);
  323.       CleartoEOLN();
  324.       (void) optionally_enter(alt_string, x, strlen(alternate_prompt)+1,
  325.          FALSE, FALSE);
  326.       return(1);
  327.     }
  328.  
  329.     CleartoEOLN();
  330.  
  331.     iindex = 0;
  332.  
  333.     if (ch == kill_line) {
  334.       MoveCursor(x,y);
  335.           CleartoEOLN();
  336.       iindex = 0;
  337.     }
  338.     else if (ch != backspace) {
  339.       if(ch == '\\') escaped = ON;
  340.       Writechar(ch);
  341.       string[iindex++] = ch;
  342.     }
  343.     else if (iindex > 0) {
  344.       iindex--;
  345.       erase_a_char();
  346.     }
  347.     else {
  348.       Writechar(' ');
  349.       Writechar(BACKSPACE);
  350.     }
  351.  
  352.     do {
  353.       fflush(stdout);
  354. /*      ch = getchar();    */
  355.       ch = ReadCh();
  356.  
  357.       /* the following is converted from a case statement to
  358.          allow the variable characters (backspace, kill_line
  359.          and break) to be processed.  Case statements in
  360.          C require constants as labels, so it failed ...
  361.       */
  362.  
  363.         if (ch == backspace &&
  364.           (!escaped || !isprint(ch)) ) {
  365.           /* This is tricky. Here we are dealing with all situations
  366.            * under which a backspace (really whatever erase char is
  367.            * set to, not necessarily \b) erases the previous character.
  368.            * It will erase unless escaped, because if it's escaped
  369.            * it is taken literally. There is one exception to that --
  370.            * if backspace would be rejected (we don't accept non-printing
  371.            * characters in non-passwd mode), we accept it here as an
  372.            * erasing character, for it if got rejected there would
  373.            * be no way of erasing a preceding backslash. */
  374.           escaped = OFF;
  375.               if (iindex > 0) {
  376.         iindex--;
  377.         erase_a_char();
  378.           }
  379.           else {
  380.         Writechar(' ');
  381.         Writechar(BACKSPACE);
  382.           }
  383.         }
  384.         else if (ch == '\l' || ch == '\r') {
  385.           escaped = OFF;
  386.           string[iindex] = '\0';
  387.           if (cursor_control)
  388.             transmit_functions(ON);
  389.           return(0);
  390.         }
  391.         else if (ch == ctrl('W')) {
  392.           escaped = OFF;
  393.           if (iindex == 0)
  394.             continue;        /* no point staying here.. */
  395.           iindex--;
  396.           if (isslash(string[iindex])) {
  397.             erase_a_char();
  398.           }
  399.           else {
  400.             while (iindex >= 0 && isspace(string[iindex])) {
  401.               iindex--;
  402.               erase_a_char();
  403.             }
  404.  
  405.             while (iindex >= 0 && ! isstopchar(string[iindex])) {
  406.               iindex--;
  407.               erase_a_char();
  408.             }
  409.             iindex++;/* and make sure we point at the first AVAILABLE slot */
  410.           }
  411.         }
  412.         else if (ch == ctrl('R')) {
  413.           escaped = OFF;
  414.           string[iindex] = '\0';
  415.           PutLine1(x,y, "%s", string);    
  416.           CleartoEOLN();
  417.         }
  418.         else if (!escaped && ch == kill_line) {
  419.           /* needed to test if escaped since kill_line character could
  420.            * be a desired valid printing character */
  421.           escaped = OFF;
  422.           MoveCursor(x,y);
  423.               CleartoEOLN();
  424.           iindex = 0;
  425.         }
  426.         else if (ch == '\0') {
  427.           escaped = OFF;
  428.           if (cursor_control)
  429.             transmit_functions(ON);
  430.           fflush(stdin);     /* remove extraneous chars, if any */
  431.           string[0] = '\0'; /* clean up string, and... */
  432.           return(-1);
  433.         }
  434.         else if (!isprint(ch)) {
  435.           /* non-printing character - warn with bell*/
  436.           /* don't turn off escaping backslash since current character
  437.            * doesn't "use it up".
  438.            */
  439.           Writechar('\007');
  440.         }
  441.         else {  /* default case */
  442.         if(escaped && (ch == backspace || ch == kill_line)) {
  443.           /* if last character was a backslash,
  444.            * and if this character is escapable
  445.            * simply write this character over it even if
  446.            * this character is a backslash.
  447.            */
  448.           Writechar(BACKSPACE);
  449.           iindex--;
  450.           string[iindex++] = ch;
  451.           Writechar(ch);
  452.           escaped = OFF;
  453.         } else {
  454.           string[iindex++] = ch;
  455.           Writechar(ch);
  456.           escaped = ( ch == '\\' ? ON : OFF);
  457.         }
  458.         }
  459.     } while (iindex < SLEN);
  460.  
  461.     string[iindex] = '\0';
  462.  
  463.     if (cursor_control)
  464.       transmit_functions(ON);
  465.     return(0);
  466. }
  467.  
  468. int
  469. GetPrompt()
  470. {
  471.     /** This routine does a read/timeout for a single character.
  472.         The way that this is determined is that the routine to
  473.         read a character is called, then the "errno" is checked
  474.         against EINTR (interrupted call).  If they match, this
  475.         returns NO_OP_COMMAND otherwise it returns the normal
  476.         command.  On BSD systems, the EINTR will never be returned
  477.         so we instead longjmp from the signal handler.
  478.     **/
  479.  
  480.     int ch;
  481.  
  482.     if (timeout > 0) {
  483.       alarm((unsigned) timeout);
  484. #ifdef    BSD
  485.       if (setjmp(GetPromptBuf)) {
  486.         InGetPrompt = 0;
  487.         ch = NO_OP_COMMAND;
  488.         alarm((unsigned) 0);
  489.       }
  490.       else {
  491.         InGetPrompt = 1;
  492.         ch = ReadCh();
  493.         InGetPrompt = 0;
  494.         alarm((unsigned) 0);
  495.       }
  496. #else
  497.         errno = 0;    /* we actually have to do this.  *sigh*  */
  498.         ch = ReadCh();
  499.         if (errno == EINTR) ch = NO_OP_COMMAND;
  500.         alarm((unsigned) 0);
  501. #endif
  502.     }
  503.     else
  504.       ch = ReadCh();
  505.  
  506.     return(ch);
  507. }
  508.