JMU
Unix Terminals
An Introduction


Prof. David Bernstein
James Madison University

Computer Science Department
bernstdh@jmu.edu


Background
Terminals as Files
The Role of Terminal Drivers
Standard Operating Modes
Setting Terminal Atrtibutes: tcsetattr() tcsetattr
int tcsetattr(int fd, int options, const struct termios *attr);
Purpose:
Set the parameters associated with the terminal
Details:
fd The open file descriptor for the terminal
options TCSANOW to make changes now; TCSADRAIN to wait until after all output is transmitted; TCSAFLUSH to both wait and discard input not received
attr The attributes to set
Return 0 on success; -1 on error
#include <termios.h> termios.h
#include <unistd.h> unistd.h
The termios Structure
  struct termios {
    tcflag_t   c_iflag;     // Input flags
    tcflag_t   c_oflag;     // Output flags
    tcflag_t   c_cflag;     // Control flags
    tcflag_t   c_lflag;     // Local modes
    cc_t       c_line;      // Do not use
    cc_t       c_cc[NCCS};  // Special characters
    speed_t    c_ispeed;    // Do not use
    speed_t    c_ospeed;    // Do not use
  }
  
Some Useful Flags
For c_iflag
ICRNL Map CR to LF (i.e., newline) on input
IGNCR Ignore CR on input
For c_lflag
ECHO Echo input characters
ICANON Canonical model input
IEXTEN Enable extended processing of input characters
ISIG Enable signal generating characters
When Does read() Return in Noncanonical Mode?
An Example: Line-Based Input
unixexamples/terminal/line.c
        #include <stdio.h>
#include <unistd.h>
#define  LENGTH 40

int
main(void)
{
  char  line[LENGTH+1];
  int   n;

  printf("%s\n", "Enter a short or long line...");

  // Note: The line-feed character is not disgarded
  n = read(STDIN_FILENO, line, LENGTH);

  // Make it a null-terminated string
  line[n] = '\0';

  printf("Line Length:   |%d|\n", n);
  printf("Line Contents: |%s|\n", line);
}
        
An Example: Character-Based Input
unixexamples/terminal/yesno.c
        #include <termios.h>
#include <unistd.h>

int
main(void)
{
  char             key; 
  struct termios   newterm, oldterm;

  tcgetattr(STDIN_FILENO, &oldterm);  // Remember the current mode

  newterm = oldterm;
  newterm.c_lflag &= ~ICANON;         // Not canonical
  newterm.c_lflag |= ECHO;            // Echo
  newterm.c_lflag |= ISIG;            // Enable QUIT, INTR, SUSP 
  newterm.c_lflag &= ~ICRNL;          // Don't map CR to LF/NL 
  newterm.c_cc[VMIN]  = 1;            // Character-at-a-time
  newterm.c_cc[VTIME] = 0;            // Do not blocking

  tcsetattr(STDIN_FILENO, TCSANOW, &newterm);

  write(STDOUT_FILENO, "Continue (Y/N)? ", 16);
  read(STDIN_FILENO, &key, 1);

  if (key == 'Y')
    {
      write(STDOUT_FILENO, "\nContinuing\n", 12);
    }
  else
    {
      write(STDOUT_FILENO, "\nStopping  \n", 12);
    }

  tcsetattr(STDIN_FILENO, TCSANOW, &oldterm);
}
        
File Type Check: isatty() isatty
int isatty(int fd);
Purpose:
Determine if a file descriptor is associated with a terminal
Details:
fd The file descriptor of interest
Return 1 (i.e., "true") if a terminal; "false" otherwise
#include <unistd.h> unistd.h
Terminal Name: ttyname() ttyname
char *ttyname(int fd);
Purpose:
Find the name of a terminal
Details:
fd The file descriptor of the terminal
Return The name of the terminal (usually in /dev or /dev/pts)
#include <unistd.h> unistd.h

This function is equivalent to the tty tty command.