chiark / gitweb /
@@@ tty cleanup
[mLib] / ui / tty.h
index e026c15a18de847d565e4512ba1ff4c85dd5d0d9..57ed4890bfbf03cef63110c44a13ab561c5b8338 100644 (file)
--- a/ui/tty.h
+++ b/ui/tty.h
@@ -162,7 +162,7 @@ enum {
 /* Other capabilities. */
 #define TTCF_RELMV     0x00000100u     /* relative cursor motion */
 #define TTCF_ABSMV     0x00000200u     /* absolute cursor motion */
-#define TTCF_MIXMV     0x00000400u     /* mixed cursor motion */
+#define TTCF_MIXMV     0x00000400u     /* mixed (y-abs, x-rel) motion */
 #define TTCF_MMARG     0x00000800u     /* proper magic margins */
 #define TTCF_BGER      0x00001000u     /* erasure uses background colour */
 #define TTCF_ERCH      0x00002000u     /* erase characters */
@@ -231,135 +231,380 @@ struct tty_state {
 
 /* Terminal control state. */
 struct tty {
-  const struct tty_ops *ops;
-  FILE *fpin, *fpout;
-  unsigned baud, ht, wd, f;
-#define TTF_BORROW 1u
-  uint32 acaps, ocaps;
-  struct tty_state st;
+  const struct tty_ops *ops;           /* operations table (opaque) */
+  FILE *fpin, *fpout;                  /* input and output streams */
+  unsigned baud;                       /* (output) baud rate (bits/s) */
+  unsigned ht, wd;                     /* terminal dimensions */
+  unsigned f;                          /* flags */
+#define TTF_BORROW 1u                  /*   don't close the streams */
+  uint32 acaps, ocaps;                /* attribute and other capabilities */
+  struct tty_state st;                 /* current terminal state */
 };
 
-struct tty_ops {
-  void (*release)(struct tty */*tty*/);
-  int (*setattr)(struct tty */*tty*/,
-                const struct gprintf_ops */*gops*/, void */*go*/,
-                const struct tty_attr */*a*/);
-  int (*setmodes)(struct tty */*tty*/,
-                 const struct gprintf_ops */*gops*/, void */*go*/,
-                 uint32 /*modes_bic*/, uint32 /*modes_xor*/);
-  int (*move)(struct tty */*tty*/,
-             const struct gprintf_ops */*gops*/, void */*go*/,
-             unsigned /*orig*/, int /*y*/, int /*x*/);
-  int (*repeat)(struct tty */*tty*/,
-               const struct gprintf_ops */*gops*/, void */*go*/,
-               int /*ch*/, unsigned /*n*/);
-  int (*erase)(struct tty */*tty*/,
-              const struct gprintf_ops */*gops*/, void */*go*/,
-              unsigned /*f*/);
-  int (*erch)(struct tty */*tty*/,
-             const struct gprintf_ops */*gops*/, void */*go*/,
-             unsigned /*n*/);
-  int (*ins)(struct tty */*tty*/,
-            const struct gprintf_ops */*gops*/, void */*go*/,
-            unsigned /*f*/, unsigned /*n*/);
-  int (*inch)(struct tty */*tty*/,
-             const struct gprintf_ops */*gops*/, void */*go*/,
-             int /*ch*/);
-  int (*del)(struct tty */*tty*/,
-            const struct gprintf_ops */*gops*/, void */*go*/,
-            unsigned /*f*/, unsigned /*n*/);
-  int (*_res0)(void), (*_res1)(void), (*_res2)(void), (*_res3)(void);
-};
+/*----- Lifecycle and maintenance -----------------------------------------*/
+
+/* --- @tty_open@ --- *
+ *
+ * Arguments:  @FILE *fp@ = stream open on terminal, or null
+ *             @unsigned f@ = flags (@TTF_...@)
+ *             @const unsigned *backends@ = ordered list of backends to try
+ *
+ * Returns:    Pointer to terminal control block, or null on error.
+ *
+ * Use:                Open a terminal and return a @struct tty *@ terminal control
+ *             block pointer.
+ *
+ *             If @fp@ is provided, then it will be used for terminal
+ *             output.  If @fp@ is @stdout@, then input (not currently
+ *             supported) will come from @stdin@; otherwise, input comes
+ *             from @fp@.  If @fp@ is null and @TTF_OPEN@ is set, then
+ *             @tty_open@ will attempt to open a terminal for itself: if
+ *             @stdin@ is interactive then it used for input; if @stdout@ --
+ *             or, failing that, @stderr@ -- is interactive, then it is used
+ *             for output; otherwise %|/dev/tty|% is opened and used.  If
+ *             @fp@ is null and @TTF_OPEN@ is not set, then a usable
+ *             terminal control block is still returned, but output cannot
+ *             be sent directly to the terminal -- since there isn't one.
+ *
+ *             If @TTF_BORROW@ is set, then the stream will not be closed by
+ *             @tty_close@.  (This flag is ignored if @fp@ is null.)
+ *
+ *             If @beckends@ is provided, then it points to a vector of
+ *             @TTBK_...@ constants describing the backends to be tried in
+ *             order.  The vector is terminated by @TTBK_END@; if this is
+ *             found, then a null pointer is returned.
+ *
+ *             A null control block pointer is valid for all @tty@
+ *             functions: most will just immediately report failure, but
+ *             there won't be any crashing.
+ */
 
-/*----- Functions provided ------------------------------------------------*/
+#define TTF_OPEN 256u                  /* open terminal if @fp@ is null */
+extern struct tty *tty_open(FILE */*fp*/, unsigned /*f*/,
+                           const unsigned */*backends*/);
 
-/* --- @tty_clampattr@ --- *
+/* --- @tty_close@ --- *
  *
- * Arguments:  @struct tty_attr *a_out@ = selected attributes
- *             @const struct tty_attr *a@ = requested attributes
- *             @uint32 acaps@ = terminal's attribute capability mask
+ * Arguments:  @struct tty *tty@ = control block pointer
  *
  * Returns:    ---
  *
- * Use:                Select the closest approximation to the requested attributes
- *             which can be accommodated by the terminal.
+ * Use:                Closes a terminal, releasing the control block and any
+ *             resources it held.  In particular, if the terminal was opened
+ *             without @TTF_BORROW@, then the output stream is closed.
  */
 
-extern void tty_clampattr(struct tty_attr */*a_out*/,
-                         const struct tty_attr */*a*/, uint32 /*acaps*/);
-
+extern void tty_close(struct tty */*tty*/);
 
+/* --- @tty_resized@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *
+ * Returns:    Zero if the size hasn't changed, %$+1$% if the size has
+ *             changed, or %$-1$% on error.
+ *
+ * Use:                Update the terminal width and height.  Call this after
+ *             receiving @SIGWINCH@, or otherwise periodically, to avoid
+ *             making a mess.
+ */
 
 extern int tty_resized(struct tty */*tty*/);
 
-#define TTF_OPEN 256u
-extern struct tty *tty_open(FILE */*fp*/, unsigned /*f*/,
-                           const unsigned */*backends*/);
+/*----- Output and control functions --------------------------------------*/
 
-extern void tty_close(struct tty */*tty*/);
+/* These functions come in pairs.  The unmarked version sends output directly
+ * to the terminal's output stream, and will obviously fail (though not
+ * crash) if this is null; the version whose names ends with @...g@ accepts
+ * an additional pair of arguments @gops@ and @go@ giving an alternative
+ * destination for output.
+ */
+
+/* --- @tty_setattr@, @tty_setattrg@--- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @const struct tty_attr *a@ = pointer to attributes to set, or
+ *                     null
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Set the indicated formatting attributes on following output.
+ *             If @a@ is null, then clear all attributes, just as if
+ *             @a->f == 0@.
+ *
+ *             If you only ever request attributes which are advertised in
+ *             the terminals capapbility masked, then you'll always get what
+ *             you asked for.  Otherwise, the provided attributes will be
+ *             `clamped', i.e., modified so as to accommodate the terminal's
+ *             shortcomings.  In simple cases, unsupported attributes may
+ *             just be dropped; but they can also be substituted, e.g.,
+ *             single underlining for double, or approximate colours for
+ *             unsupported colours.
+ */
 
+extern int tty_setattr(struct tty */*tty*/, const struct tty_attr */*a*/);
 extern int tty_setattrg(struct tty */*tty*/,
                        const struct gprintf_ops */*gops*/, void */*go*/,
                        const struct tty_attr */*a*/);
 
-extern int tty_setattr(struct tty */*tty*/, const struct tty_attr */*a*/);
+/* --- @tty_setattrlist@, @tty_setattrlistg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @const struct tty_attrlist *aa@ = pointer to attribute list
+ *                     `menu'
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Search the list for an entry matching the terminal's
+ *             capabilities, i.e., @tty->acaps&a->cap_mask == a->cap_eq@.
+ *             The attributes in the first such entry are set, as if by
+ *             @tty_setattr@.
+ *
+ *             The list is terminated by an entry with @cap_mask == 0@ --
+ *             though it will be checked like any other before ending the
+ *             search.  In particular, this means that an entry with
+ *             @cap_mask == cap_eq == 0@ is a `catch-all', and its
+ *             attributes will be set if no earlier matching entry could be
+ *             found, while an entry with @cap_mask == 0@ and @cap_eq != 0@
+ *             terminates the search without setting any attributes.
+ */
 
+extern int tty_setattrlist(struct tty */*tty*/,
+                          const struct tty_attrlist */*aa*/);
 extern int tty_setattrlistg(struct tty */*tty*/,
                            const struct gprintf_ops */*gops*/, void */*go*/,
                            const struct tty_attrlist */*aa*/);
 
-extern int tty_setattrlist(struct tty */*tty*/,
-                          const struct tty_attrlist */*aa*/);
+/* --- @tty_setmodes@, @tty_setmodesg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @uint32 modes_bic, modes_xor@ = masks to apply to the modes
+ *                     settings
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Adjust the terminal display modes: specifically, the modes
+ *             are adjusted to be @(modes&~modes_bic) ^ modes_xor@.
+ *             Mode bits which aren't supported by the terminal are
+ *             ignored.
+ */
 
+extern int tty_setmodes(struct tty */*tty*/,
+                       uint32 /*modes_bic*/, uint32 /*modes_xor*/);
 extern int tty_setmodesg(struct tty */*tty*/,
                         const struct gprintf_ops */*gops*/, void */*go*/,
                         uint32 /*modes_bic*/, uint32 /*modes_xor*/);
 
-extern int tty_setmodes(struct tty */*tty*/,
-                       uint32 /*modes_bic*/, uint32 /*modes_xor*/);
+/* --- @tty_move@, @tty_moveg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @unsigned orig@ = origin
+ *             @int y, x@ = new cursor position
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Move the cursor.  Coordinates are numbered starting with 0.
+ *
+ *             The @y@ position is interpreted relative to the origin given
+ *             by @orig@: if @TTOF_YCUR@ is set, then the motion is relative
+ *             to the current cursor row; otherwise, it is relative to
+ *             the top `home' row.  Similarly, the @x@ position is
+ *             interpreted relative to the current cursor column if
+ *             @TTOF_XCUR is set, otherwise relative to the leftmost
+ *             column.
+ *
+ *             Not all terminals are capable of all kinds of motions:
+ *             @TTCF_ABSMV@ is set if absolute motion is possible, and
+ *             @TTCF_RELMV@ is set if relative motion is possible.  The
+ *             @TTCF_MIXMV@ bit indicates that the combination of absolute-y
+ *             and relative-x motion is possible; note that the combination
+ *             of relative-y and absolute-x is always possible if relative
+ *             motion is possible at all.
+ *
+ *             The above notwithstanding, all terminals are assumed capable
+ *             of moving the cursor to the start of either the current line
+ *             @tty_move(tty, TTOF_YCUR | TTOF_XHOME, 0, 0)@, or of the next
+ *             line @tty_move(tty, TTOF_YCUR | TTOF_XHOME, +1, 0)@.
+ */
 
+extern int tty_move(struct tty */*tty*/,
+                   unsigned /*orig*/, int /*y*/, int /*x*/);
 extern int tty_moveg(struct tty */*tty*/,
                     const struct gprintf_ops */*gops*/, void */*go*/,
                     unsigned /*orig*/, int /*y*/, int /*x*/);
 
-extern int tty_move(struct tty */*tty*/,
-                   unsigned /*orig*/, int /*y*/, int /*x*/);
+/* --- @tty_repeat@, @tty_repeatg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @int ch@ = character to write
+ *             @unsigned n@ = number of copies
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Write @n@ copies of the character @ch@ to the terminal.
+ *             (Some terminals have a special control sequence for doing
+ *             this.)
+ */
 
+extern int tty_repeat(struct tty */*tty*/, int /*ch*/, unsigned /*n*/);
 extern int tty_repeatg(struct tty */*tty*/,
                       const struct gprintf_ops */*gops*/, void */*go*/,
                       int /*ch*/, unsigned /*n*/);
 
-extern int tty_repeat(struct tty */*tty*/, int /*ch*/, unsigned /*n*/);
+/* --- @tty_erase@, @tty_eraseg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @unsigned f@ = flags
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Erase portions of the current line or the whole display.
+ *
+ *             If @TTEF_DSP@ is set, then the whole display is affected.  If
+ *             @TTEF_BEGIN@ is set, then the display is erased starting from
+ *             the top left and ending at and including the cursor
+ *             position.  If @TTEF_END@ is set, then the display is erased
+ *             starting from and including the cursor position, and ending
+ *             at the bottom right.  If both flags are set, then,
+ *             additionally, the cursor is moved to its `home' position at
+ *             the top left.
+ *
+ *             If @TTF_DSP@ is not set, then the current line is affected.
+ *             If @TTEF_BEGIN@ is set, then the line is erased starting from
+ *             the left and ending at and including the cursor position.  If
+ *             @TTEF_END@ is set, then the line is erased starting from and
+ *             including the cursor position, and ending at the right hand
+ *             side.
+ *
+ *             If the @TTCF_BGER@ capability is set, then the erased
+ *             positions take on the current background colour; otherwise,
+ *             they have the default background colour.
+ */
 
+extern int tty_erase(struct tty */*tty*/, unsigned /*f*/);
 extern int tty_eraseg(struct tty */*tty*/,
                      const struct gprintf_ops */*gops*/, void */*go*/,
                      unsigned /*f*/);
 
-extern int tty_erase(struct tty */*tty*/, unsigned /*f*/);
+/* --- @tty_erch@, @tty_erchg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @unsigned n@ = number of characters to erase
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Erase a number of characters, starting from and including the
+ *             current cursor position.
+ *
+ *             If the @TTCF_BGER@ capability is set, then the erased
+ *             positions take on the current background colour; otherwise,
+ *             they have the default background colour.
+ */
 
+extern int tty_erch(struct tty */*tty*/, unsigned /*n*/);
 extern int tty_erchg(struct tty */*tty*/,
                     const struct gprintf_ops */*gops*/, void */*go*/,
                     unsigned /*n*/);
 
-extern int tty_erch(struct tty */*tty*/, unsigned /*n*/);
+/* --- @tty_ins@, @tty_insg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @unsigned f@ = flags
+ *             @unsigned n@ = number of items to insert
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Insert a number of blank characters or lines.
+ *
+ *             If @TTIDF_LN@ is set, then insert @n@ blank lines above the
+ *             current line.  The cursor must be at the far left of the
+ *             line.
+ *
+ *             Otherwise, insert @n@ empty character spaces at the cursor
+ *             position.
+ */
 
+extern int tty_ins(struct tty */*tty*/, unsigned /*f*/, unsigned /*n*/);
 extern int tty_insg(struct tty */*tty*/,
                    const struct gprintf_ops */*gops*/, void */*go*/,
                    unsigned /*f*/, unsigned /*n*/);
 
-extern int tty_ins(struct tty */*tty*/, unsigned /*f*/, unsigned /*n*/);
+/* --- @tty_inch@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @int ch@ = character to insert
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Insert a single character.
+ *
+ *             If the @TTMF_INS@ mode is advertised, then insert mode must
+ *             be set before calling this function.
+ */
 
+extern int tty_inch(struct tty */*tty*/, int /*ch*/);
 extern int tty_inchg(struct tty */*tty*/,
                     const struct gprintf_ops */*gops*/, void */*go*/,
                     int /*ch*/);
 
-extern int tty_inch(struct tty */*tty*/, int /*ch*/);
+/* --- @tty_del@, @tty_delg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @unsigned f@ = flags
+ *             @unsigned n@ = number of items to delete
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Delete a number of characters or lines.
+ *
+ *             If @TTIDF_LN@ is set, then delete @n@ blank lines, starting
+ *             with the current line line.  The cursor must be at the far
+ *             left of the line.
+ *
+ *             Otherwise, delete @n@ characters at the cursor position.
+ */
 
+extern int tty_del(struct tty */*tty*/, unsigned /*f*/, unsigned /*n*/);
 extern int tty_delg(struct tty */*tty*/,
                    const struct gprintf_ops */*gops*/, void */*go*/,
                    unsigned /*f*/, unsigned /*n*/);
 
-extern int tty_del(struct tty */*tty*/, unsigned /*f*/, unsigned /*n*/);
+/* --- @tty_restore@, @tty_restoreg@ --- *
+ *
+ * Arguments:  @struct tty *tty@ = control block pointer
+ *             @const struct gprintf_ops *gops, void *go@ = output
+ *                     destination
+ *             @const struct tty_state *st@ = state to restore
+ *
+ * Returns:    Zero on success, %$-1$% on error.
+ *
+ * Use:                Restore the terminal modes and attributes to match a
+ *             state previously captured by copying @tty->st@.
+ */
+
+extern int tty_restore(struct tty */*tty*/, const struct tty_state */*st*/);
+extern int tty_restoreg(struct tty */*tty*/,
+                       const struct gprintf_ops */*gops*/, void */*go*/,
+                       const struct tty_state */*st*/);
 
 /*----- That's all, folks -------------------------------------------------*/