1
0
Files
irix-657m-src/eoe/cmd/bru/tty.c
2022-09-29 17:59:04 +03:00

497 lines
12 KiB
C
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/************************************************************************
* *
* Copyright (c) 1984, Fred Fish *
* All Rights Reserved *
* *
* This software and/or documentation is protected by U.S. *
* Copyright Law (Title 17 United States Code). Unauthorized *
* reproduction and/or sales may result in imprisonment of up *
* to 1 year and fines of up to $10,000 (17 USC 506). *
* Copyright infringers may also be subject to civil liability. *
* *
************************************************************************
*/
/*
* FILE
*
* tty.c routines for interacting with user's terminal
*
* SCCS
*
* @(#)tty.c 9.11 5/11/88
*
* DESCRIPTION
*
* Contains routines which directly interact with the user's
* terminal.
*
*/
#include "autoconfig.h"
#include <stdarg.h> /* Use system supplied varargs */
#include <stdio.h>
#if (unix || xenix)
# include <sys/types.h>
# include <sys/stat.h>
# if HAVE_TERMIO
# include <termio.h> /* For terminal handling */
# else
# include <sgtty.h> /* For terminal handling */
# include <sys/file.h> /* For ioctl flags */
# endif
#endif
#include "typedefs.h" /* Locally defined types */
#include "dbug.h"
#include "manifest.h" /* Manifest constants */
#include "config.h" /* Configuration file */
#include "errors.h" /* Error codes */
#include "finfo.h" /* File information structure */
#include "flags.h" /* Command line flags */
#include "bruinfo.h" /* Current invocation information */
/*
* External bru variables.
*/
static FILE *ttyout; /* Stream for writing requests */
static FILE *ttyin; /* Stream for reading responses */
extern struct cmd_flags flags; /* Command line flags */
extern struct bru_info info; /* Current invocation information */
/*
* External bru functions.
*/
extern VOID bru_error (); /* Report an error to user */
extern VOID sig_push (); /* Push current signal state */
extern VOID sig_pop (); /* Pop previous signal stat */
extern VOID sig_done (); /* Set for unconditional exit via "done" */
extern VOID done (); /* Clean up and exit with status */
extern VOID s_sleep (); /* Sleep for specified number of seconds */
#define tty_putc(a) s_putc(a,ttyout)
#define tty_getc() s_getc(ttyin)
#define tty_rewind s_rewind
extern int s_getc (); /* Get character from a stream */
extern int s_putc (); /* Write character to stream */
extern VOID s_fflush (); /* Invoke library fflush function */
extern VOID s_rewind (); /* Switch between read/write (YECH!) */
extern FILE *s_fopen (); /* Open a stream */
extern int s_vfprintf (); /* Invoke library vfprintf function */
extern int s_ioctl (); /* Request to control device */
extern int s_fileno (); /* Convert FILE pointer to file descriptor */
/*
* Locally defined functions.
*/
static VOID tty_open (); /* Open the terminal file */
static VOID tty_inflush (); /* Flush tty input stream */
char *tty_read (); /* Read from tty stream into buffer */
VOID tty_fflush ()
{
if (ttyout != NULL) {
s_fflush (ttyout);
}
}
/*VARARGS1*/
VOID tty_printf (char *str, ...)
{
va_list args;
/* this can get called from signal handlers and other places before
the tty is tty_open()'ed. Either open it here, or ignore the
call. Since bru crashed in these cases before, there was obviously
never any output, so I chose to ignore the call. Olson, 11/88
*/
if(ttyout) {
va_start (args, str);
(VOID) s_vfprintf (ttyout, str, args);
va_end (args);
}
}
/*
* FUNCTION
*
* confirmed confirm an action if confirmation enabled
*
* SYNOPSIS
*
* BOOLEAN confirmed (format, fip)
* char *format;
* struct finfo *fip;
*
* DESCRIPTION
*
* Given pointer to a printf style format string representing
* action to be taken, and pointer to a file information structure,
* confirms the action and returns TRUE or FALSE according to
* "yes" or "no" response.
*
*/
/*
* PSEUDO CODE
*
* Begin confirmed
* Default result is confirm action
* If confirmation requested and terminal available then
* Print action to be taken
* Print confirmation request
* Get answer from user
* Determine result
* End if
* Return result
* End confirmed
*
*/
BOOLEAN confirmed (format, fip)
char *format;
struct finfo *fip;
{
auto char answer [NAMESIZE];
register BOOLEAN result;
DBUG_ENTER ("confirmed");
result = TRUE;
if (flags.wflag) {
if (ttyout == NULL) {
tty_open ();
}
tty_printf (format, fip -> fname);
tty_printf (": please confirm [y/n] ");
(VOID) tty_read (answer, sizeof (answer));
result = (answer[0] == 'y' || answer[0] == 'Y');
}
DBUG_RETURN (result);
}
/*
* FUNCTION
*
* response get response from user to a prompt
*
* SYNOPSIS
*
* char response (prompt, dfault)
* char *prompt;
* char dfault;
*
* DESCRIPTION
*
* Given pointer to a prompt for user, and a default response,
* prompts user and returns a single character indicating the
* response. If the response is simply a carriage return, the
* the default is returned.
*
*/
/*
* PSEUDO CODE
*
* Begin response
* Save previous signal handling state
* Set up to exit on interrupt or quit
* Issue prompt to user
* Read the answer
* Pop the previous signal handling state
* If no explicit answer given then
* Result is the default
* End if
* Return the answer
* End response
*
*/
char response (prompt, dfault)
char *prompt;
char dfault;
{
SIGTYPE prevINT;
SIGTYPE prevQUIT;
auto char answer [2];
DBUG_ENTER ("response");
sig_push (&prevINT, &prevQUIT);
sig_done ();
if (ttyout == NULL) {
tty_open ();
}
tty_printf ("%s: %s [default: %c] >> ", info.bru_name, prompt, dfault);
(VOID) tty_read (answer, sizeof (answer));
sig_pop (&prevINT, &prevQUIT);
if (answer[0] == EOS) {
answer[0] = dfault;
}
DBUG_RETURN (answer[0]);
}
/*
* FUNCTION
*
* tty_read read a string from the user's terminal
*
* SYNOPSIS
*
* char *tty_read (bufp, tbufsize)
* char *bufp;
* int tbufsize;
*
* DESCRIPTION
*
* Given pointer to a buffer in which to store a response string,
* and the size of the buffer, reads from the tty up to the
* limit imposed by the buffer. Then flushes the rest of
* the input.
*
* The rewind call is necessary to allow mixed reads/writes
* on the terminal. Systems which don't allow this use
* two separate streams.
*
* Returns pointer to the terminating null character in buffer
* or returns NULL if too much input was read for available
* buffer.
*
* Note that it is not an error to provide a NULL pointer for
* the buffer. In this case, all input is discarded up to the
* next newline and a NULL is returned. This is useful in
* those situations where operation is suspended until the
* user issues an acknowledgement.
*
* The -B option (background) is provided for cases where the prefered
* action is to simply give up rather than attempting to interact with
* the operator. This might occur, for example, when bru is
* used in a shell script that must be run at night with no operator
* present, and the script must not hang waiting for input.
* In this case, bru just issues an appropriate message and exits
* with an error status.
*
*/
/*
* PSEUDO CODE
*
* Begin tty_read
* If abort rather than interact with operator
* Finish interaction line with a newline
* Issue appropriate error message
* Clean up and exit
* Else
* Flush any pending output to terminal
* Flush any pending input if possible
* Rewind the terminal (huh!)
* If no buffer or illegal buffer size then
* Flush any input
* Return will be NULL
* Else
* While more input and place to put it
* Squirrel the character away in buffer
* End while
* Terminate the string in the buffer
* If last character was not end of input then
* Remember we overran the buffer
* Flush any remaining input on line
* End if
* Endif
* Rewind the terminal
* End if
* Return result
* End tty_read
*
*/
char *tty_read (bufp, tbufsize)
char *bufp;
int tbufsize;
{
register char ch;
DBUG_ENTER ("tty_read");
if (flags.Bflag) {
tty_printf ("\n");
bru_error (ERR_BACKGND);
done ();
} else {
tty_fflush ();
tty_inflush ();
tty_rewind (ttyout);
if (bufp == NULL || tbufsize < 1) {
while (tty_getc () != '\n') {;}
bufp = NULL;
} else {
while (((ch = tty_getc ()) != '\n') && --tbufsize) {
*bufp++ = ch;
}
*bufp = EOS;
if (ch != '\n') {
bufp = NULL;
while (tty_getc () != '\n') {;}
}
}
tty_rewind (ttyin);
}
DBUG_RETURN (bufp);
}
/*
* FUNCTION
*
* tty_inflush flush the tty input queue if possible
*
* SYNOPSIS
*
* static VOID tty_inflush
*
* DESCRIPTION
*
* This function is called to flush the input queue, if
* possible, before each interactive prompt. This insures
* that no stray typeaheads will cause unintentional results.
* This function can be null without any serious adverse
* affects on functionality.
*
* Under BSD 4.2, be sure to flush only the input queue.
*/
static VOID tty_inflush ()
{
DBUG_ENTER ("tty_inflush");
#ifdef TCFLSH
(VOID) s_ioctl (s_fileno (ttyin), TCFLSH, 0);
#else
#ifdef TIOCFLUSH
{
int tflags;
tflags = FREAD;
(VOID) s_ioctl (s_fileno (ttyin), (int) TIOCFLUSH, (int) &tflags);
}
#endif
#endif
DBUG_VOID_RETURN;
}
/*
* FUNCTION
*
* tty_open open the tty file for possible interaction with user
*
* SYNOPSIS
*
* static VOID tty_open ()
*
* DESCRIPTION
*
* Opens the user's terminal file for possible interaction later.
* Not every invocation of bru will require interaction. Failure
* to open the prefered file will result in a warning and
* execution will continue using standard error instead.
*
* This function is generally called only once per bru
* invocation, when it is discovered that the current tty pointer
* is NULL.
*
* Note that if the -B option has been specified, there is to
* be no interaction with the operator. Thus we simply allow the
* interaction stream to default to stderr so that the message
* we need an answer to will get written to wherever the errors
* are going.
*
*/
static VOID tty_open ()
{
DBUG_ENTER ("tty_open");
if (!flags.Bflag && ttyout == NULL && ttyin == NULL) {
if ((ttyout = s_fopen (info.bru_tty, "r+")) == NULL)
bru_error (ERR_TTYOPEN, info.bru_tty);
ttyin = ttyout;
}
if (ttyout == NULL) {
ttyout = stderr;
ttyin = ttyout;
info.bru_tty = "stderr";
}
DBUG_VOID_RETURN;
}
/*
* FUNCTION
*
* tty_newmedia prompt for new media and device name
*
* SYNOPSIS
*
* VOID tty_newmedia (volume, dfault, newname, newnamesize)
* int volume;
* char *dfault;
* char *newname;
* int newnamesize;
*
* DESCRIPTION
*
* Rings the terminal bell and prompts the user for a new media
* for the given volume number. If dfault is non-null then
* the default is also shown. Any input from the user is placed
* in the buffer pointed to by newname, of size newnamesize.
*
* There is a 1 second delay after sending out the BELL character
* because some terminals or systems seem to require a long
* time to process it and may drop characters in the meantime.
*
*/
VOID tty_newmedia (volume, dfault, newname, newnamesize)
int volume;
char *dfault;
char *newname;
int newnamesize;
{
DBUG_ENTER ("tty_newmedia");
if (ttyout == NULL) {
tty_open ();
}
#ifdef LATTICE /* Lattice bug, report it... */
tty_putc (BELL);
#else
(VOID) tty_putc (BELL);
#endif
tty_fflush ();
s_sleep ((UINT) 1);
tty_printf ("%s: load volume %d and enter device",
info.bru_name, volume);
if (dfault != NULL) {
tty_printf (" [default: %s]", dfault);
}
tty_printf (" >> ");
(VOID) tty_read (newname, newnamesize);
DBUG_VOID_RETURN;
}