/* Terminal handling. Copyright 2002 Johan Rydberg, jrydberg@rtmk.org. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* This file is from the GNU Hurd project (modified of course) Copyright (C) 1995, 1996, 1999 Free Software Foundation, Inc. Written by Michael I. Bushnell, p/BSG. */ #ifndef _TERM_H #define _TERM_H 1 #include #include #include #include #include #include #if 0 #undef MDMBUF #undef ECHO #undef TOSTOP #undef FLUSHO #undef PENDIN #undef NOFLSH #endif #include #define CHAR_EOT '\004' /* C-d */ #define CHAR_DC1 '\021' /* C-q */ #define CHAR_DC2 '\022' /* C-r */ #define CHAR_DC3 '\023' /* C-s */ #define CHAR_USER_QUOTE '\377' /* break quoting, etc. */ /* This bit specifies control */ #define CTRL_BIT 0x40 /* XXX These belong in */ #ifdef IUCLC #define ILCASE IUCLC #else #define ILCASE (1 << 14) #endif #ifdef OLCUC #define OLCASE OLCUC #else #define OLCASE (1 << 9) #endif #define OTILDE (1 << 10) /* used in mdmctl device call */ #define MDMCTL_BIS 0 #define MDMCTL_BIC 1 #define MDMCTL_SET 2 #define USER_OUTPUT_SUSP 0x00000001 /* user has suspended output */ #define TTY_OPEN 0x00000002 /* someone has us open */ #define LAST_SLASH 0x00000004 /* last input char was \ */ #define LAST_LNEXT 0x00000008 /* last input char was VLNEXT */ #define INSIDE_HDERASE 0x00000010 /* inside \.../ hardcopy erase pair */ #define SENT_VSTOP 0x00000020 /* we've sent VSTOP to IXOFF peer */ #define FLUSH_OUTPUT 0x00000040 /* user wants output flushed */ #define NO_CARRIER 0x00000080 /* carrier is absent */ #define EXCL_USE 0x00000100 /* user accessible exclusive use */ #define NO_OWNER 0x00000200 /* there is no foreground_id */ #define ICKY_ASYNC 0x00000400 /* some user has set O_ASYNC */ #define QUEUE_LOWAT 100 #define QUEUE_HIWAT 300 struct term { /* Global lock */ pthread_mutex_t global_lock; /* Directly user-visible state */ struct termios termstate; /* Other state with the following bits: */ long termflags; /* The queues we use */ struct queue *inputq, *rawq, *outputq; /* Plain pass-through input */ int remote_input_mode; /* External processing mode */ int external_processing; /* Wakeup when NO_CARRIER turns off */ pthread_cond_t carrier_alert; /* Wakeup for select */ pthread_cond_t select_alert; /* Terminal owner */ uid_t term_owner; /* Terminal group */ uid_t term_group; /* Terminal mode */ mode_t term_mode; /* Per-device specific data */ void *term_aux; /* Bottomhalf */ struct bottomhalf *bottom; /* Number of characters in the rawq which have been echoed continuously without intervening output. */ int echo_qsize; /* Where the output_psize was when echo_qsize was last 0. */ int echo_pstart; /* PHYSICAL position of the terminal cursor */ int output_psize; }; /* Place newly input character C on the input queue. If all remaining pending input characters should be dropped, return 1; else return 0. */ int input_character (struct term *term, int c); /* Place C on output queue, doing normal processing. */ void write_character (struct term *term, int c); /* This is called by the lower half when a break is received. */ void input_break (struct term *term); /* Called when a character is recived with a framing error. */ void input_framing_error (struct term *term, int c); /* Allocate a new terminal. BOTTOM is the bottomhalf for the terminal. Will set TERM_AUX to AUX. */ struct term *term_allocate (struct bottomhalf *bottom, void *aux); /* Functions a bottom half defines */ struct bottomhalf { void (*start_output) (struct term *); void (*set_break) (struct term *); void (*clear_break) (struct term *); void (*abandon_physical_output) (struct term *); void (*suspend_physical_output) (struct term *); int (*pending_output_size) (struct term *); void (*notice_input_flushed) (struct term *); error_t (*assert_dtr) (struct term *); void (*desert_dtr) (struct term *); void (*set_bits) (struct term *); void (*mdmctl) (struct term *, int, int); int (*mdmstate) (struct term *); }; /* Character queues */ #define QUEUE_QUOTE_MARK 0xf000 typedef short quoted_char; struct queue { int susp; int lowat; int hiwat; short *cs, *ce; int arraylen; pthread_cond_t wait; quoted_char array[0]; }; struct queue *create_queue (int size, int lowat, int hiwat); /* Return the number of characters in Q. */ extern inline int qsize (struct queue *q) { return q->ce - q->cs; } /* Return nonzero if characters can be added to Q. */ extern inline int qavail (struct queue *q) { return !q->susp; } /* Flush all the characters from Q. */ extern inline void clear_queue (struct queue *q) { q->susp = 0; q->cs = q->ce = q->array; pthread_cond_broadcast (&q->wait); } /* Should be below, but inlines need it. */ void call_asyncs (int dir); /* Return the next character off Q; leave the quoting bit on. */ extern inline quoted_char dequeue_quote (struct term *term, struct queue *q) { int beep = 0; assert (qsize (q)); if (q->susp && (qsize (q) < q->lowat)) { q->susp = 0; beep = 1; } if (qsize (q) == 1) beep = 1; /* ??? for some reason _cond_broadcast failes in this one. might be a bug in the thread library !! fix this. */ if (beep) pthread_cond_signal (&q->wait); return *q->cs++; } /* Return the next character off Q. */ extern inline char dequeue (struct term *term, struct queue *q) { return dequeue_quote (term, q) & ~QUEUE_QUOTE_MARK; } struct queue *reallocate_queue (struct queue *); /* Add C to *QP. */ extern inline void enqueue_internal (struct term *term, struct queue **qp, quoted_char c) { struct queue *q = *qp; if (q->ce - q->array == q->arraylen) q = *qp = reallocate_queue (q); *q->ce++ = c; /* ??? for some reason _cond_broadcast failes in this one. might be a bug in the thread library !! fix this. */ if (qsize (q) == 1) pthread_cond_signal (&q->wait); if (!q->susp && (qsize (q) > q->hiwat)) q->susp = 1; } /* Add C to *QP. */ extern inline void enqueue (struct term *term, struct queue **qp, char c) { enqueue_internal (term, qp, c); } /* Add C to *QP, marking it with a quote. */ extern inline void enqueue_quote (struct term *term, struct queue **qp, char c) { enqueue_internal (term, qp, c | QUEUE_QUOTE_MARK); } /* Return the unquoted version of a quoted_char. */ extern inline char unquote_char (quoted_char c) { return c & ~QUEUE_QUOTE_MARK; } /* Tell if a quoted_char is actually quoted. */ extern inline int char_quoted_p (quoted_char c) { return c & QUEUE_QUOTE_MARK; } /* Remove the most recently enqueue character from Q; leaving the quote mark on. */ extern inline short queue_erase (struct queue *q) { short answer; int beep = 0; assert (qsize (q)); answer = *--q->ce; if (q->susp && (qsize (q) < q->lowat)) { q->susp = 0; beep = 1; } if (qsize (q) == 0) beep = 1; if (beep) pthread_cond_broadcast (&q->wait); return answer; } #endif /* term.h */