ttsl_drv.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 743 行 · 第 1/2 页
C
743 行
/* ``The contents of this file are subject to the Erlang Public License, * Version 1.1, (the "License"); you may not use this file except in * compliance with the License. You should have received a copy of the * Erlang Public License along with this software. If not, it can be * retrieved via the world wide web at http://www.erlang.org/. * * Software distributed under the License is distributed on an "AS IS" * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See * the License for the specific language governing rights and limitations * under the License. * * The Initial Developer of the Original Code is Ericsson Utvecklings AB. * Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings * AB. All Rights Reserved.'' * * $Id$ *//* * Tty driver that reads one character at the time and provides a * smart line for output. */#ifdef HAVE_CONFIG_H# include "config.h"#endif#include "sys.h"#include <ctype.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <signal.h>#include <fcntl.h>#include <locale.h>#include <unistd.h>#include <termios.h>#include "erl_driver.h"#define TRUE 1#define FALSE 0/* Termcap functions. */int tgetent(char* bp, char *name);int tgetnum(char* cap);int tgetflag(char* cap);char *tgetstr(char* cap, char** buf);char *tgoto(char* cm, int col, int line);int tputs(char* cp, int affcnt, int (*outc)(int c));/* Terminal capabilites in which we are interested. */static char *capbuf;static char *up, *down, *left, *right;static int cols, xn;/* The various opcodes. */#define OP_PUTC 0#define OP_MOVE 1#define OP_INSC 2#define OP_DELC 3#define OP_BEEP 4static int lbuf_size = BUFSIZ;#define MAXSIZE (1 << 16)static byte *lbuf; /* The current line buffer */static int llen; /* The current line length */static byte *lc; /* The current character pointer */static int lpos;#define COL(_l) ((_l) % cols)#define LINE(_l) ((_l) / cols)#define PAD '\n'#define NL '\n'/* Main interface functions. */static int ttysl_init(void);static ErlDrvData ttysl_start(ErlDrvPort, char*);static void ttysl_stop(ErlDrvData);static void ttysl_from_erlang(ErlDrvData, char*, int);static void ttysl_from_tty(ErlDrvData, ErlDrvEvent);static Sint16 get_sint16(char*);static ErlDrvPort ttysl_port;static int ttysl_fd;static FILE *ttysl_out;/* Functions that work on the line buffer. */static int start_lbuf(void);static int stop_lbuf(void);static int put_chars(byte*,int);static int move_rel(int);static int ins_chars(byte*,int);static int del_chars(int);static byte *step_over_chars(int);static int insert_buf(byte*,int);static int write_buf(byte*,int);static int outc(int c);static int move_cursor(int,int);/* Termcap functions. */static int start_termcap(void);static int stop_termcap(void);static int move_left(int);static int move_right(int);static int move_up(int);static int move_down(int);/* Terminal setting functions. */static int tty_init(int,int,int,int);static int tty_set(int);static int tty_reset(int);static RETSIGTYPE suspend(int);static RETSIGTYPE cont(int);/* Define the driver table entry. */struct erl_drv_entry ttsl_driver_entry = { ttysl_init, ttysl_start, ttysl_stop, ttysl_from_erlang, ttysl_from_tty, NULL, "tty_sl" };static int ttysl_init(void){ ttysl_port = (ErlDrvPort)-1; ttysl_fd = -1; lbuf = NULL; /* For line buffer handling */ capbuf = NULL; /* For termcap handling */ return TRUE;}static ErlDrvData ttysl_start(ErlDrvPort port, char* buf){ char *s, *t, c; int canon, echo, sig; /* Terminal characteristics */ int flag; extern int using_oldshell; /* set this to let the rest of erts know */ if (ttysl_port != (ErlDrvPort)-1) return ERL_DRV_ERROR_GENERAL; if (!isatty(0) || !isatty(1)) return ERL_DRV_ERROR_GENERAL; /* Set the terminal modes to default leave as is. */ canon = echo = sig = 0; /* Parse the input parameters. */ for (s = strchr(buf, ' '); s; s = t) { s++; /* Find end of this argument (start of next) and insert NUL. */ if ((t = strchr(s, ' '))) { c = *t; *t = '\0'; } if ((flag = ((*s == '+') ? 1 : ((*s == '-') ? -1 : 0)))) { if (s[1] == 'c') canon = flag; if (s[1] == 'e') echo = flag; if (s[1] == 's') sig = flag; } else if ((ttysl_fd = open(s, O_RDWR, 0)) < 0) return ERL_DRV_ERROR_GENERAL; } if (ttysl_fd < 0) ttysl_fd = 0; if (tty_init(ttysl_fd, canon, echo, sig) < 0 || tty_set(ttysl_fd) < 0) { ttysl_port = (ErlDrvPort)-1; tty_reset(ttysl_fd); return ERL_DRV_ERROR_GENERAL; } /* Set up smart line and termcap stuff. */ if (!start_lbuf() || !start_termcap()) { stop_lbuf(); /* Must free this */ tty_reset(ttysl_fd); return ERL_DRV_ERROR_GENERAL; } /* Open the terminal and set the terminal */ ttysl_out = fdopen(ttysl_fd, "w"); setlocale(LC_CTYPE, ""); /* Set international environment */ sys_sigset(SIGCONT, cont); driver_select(port, (ErlDrvEvent)(Uint)ttysl_fd, DO_READ, 1); ttysl_port = port; /* we need to know this when we enter the break handler */ using_oldshell = 0; return (ErlDrvData)ttysl_port; /* Nothing important to return */}static void ttysl_stop(ErlDrvData ttysl_data){ if (ttysl_port != (ErlDrvPort)-1) { stop_lbuf(); stop_termcap(); tty_reset(ttysl_fd); if (ttysl_fd != 0) close(ttysl_fd); driver_select(ttysl_port, (ErlDrvEvent)(Uint)ttysl_fd, DO_READ, 0); sys_sigset(SIGCONT, SIG_DFL); } ttysl_port = (ErlDrvPort)-1; ttysl_fd = -1; /* return TRUE; */}/* * Check that there is enough room in all buffers to copy all pad chars * and stiff we need If not, realloc lbuf. */static int check_buf_size(byte *s, int n){ int size; byte *tmp, *old_lbuf; size = 10; for (tmp = s; n > 0; --n, tmp++) { if (isprint(*tmp)) size++; else if (*tmp == '\t') size += 8; else if (*tmp >= 128) size += 4; else size += 2; } if (size + lpos >= lbuf_size) { lbuf_size = size + lpos + BUFSIZ; old_lbuf = lbuf; if ((lbuf = driver_realloc(lbuf, lbuf_size)) == NULL) { driver_failure(ttysl_port, -1); return(0); } lc = lbuf + (lc - old_lbuf); } return(1);}static void ttysl_from_erlang(ErlDrvData ttysl_data, char* buf, int count){ if (lpos > MAXSIZE) put_chars((byte*)"\n", 1); if (check_buf_size((byte*)buf+1, count-1) == 0) return; /*(-1); */ switch (buf[0]) { case OP_PUTC: put_chars((byte*)buf+1, count-1); break; case OP_MOVE: move_rel(get_sint16(buf+1)); break; case OP_INSC: ins_chars((byte*)buf+1, count-1); break; case OP_DELC: del_chars(get_sint16(buf+1)); break; case OP_BEEP: outc('\007'); break; default: /* Unknown op, just ignore. */ break; } fflush(ttysl_out); return; /* TRUE; */}static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd){ char b[1024]; ssize_t i; if ((i = read((int)(Sint)fd, b, 1024)) >= 0) driver_output(ttysl_port, b, i); else driver_failure(ttysl_port, -1); /* return TRUE;*/}/* Procedures for putting and getting integers to/from strings. */static Sint16 get_sint16(char *s){ return ((*s << 8) | ((byte*)s)[1]);}static int start_lbuf(void){ if (!lbuf && !(lbuf = (byte*) driver_alloc(lbuf_size))) return FALSE; llen = 0; lc = lbuf; lpos = 0; return TRUE;}static int stop_lbuf(void){ if (lbuf) driver_free(lbuf); lbuf = NULL; return TRUE;}/* Put l characters from s into the buffer and output them. */static int put_chars(byte *s, int l){ int n; n = insert_buf(s, l); if (n > 0) write_buf(lc - n, n); if (lpos > llen) llen = lpos; return TRUE;}/* * Move the current postition forwards or backwards within the current * line. We know about padding. */static int move_rel(int n){ int npos; /* The new position */ byte *c; /* Step forwards or backwards over the buffer. */ c = step_over_chars(n); /* Calculate move, updates pointers and move the cursor. */ npos = c > lc ? lpos + (c - lc) : lpos - (lc - c); move_cursor(lpos, npos); lc = c; lpos = npos; return TRUE;}/* Insert characters into the buffer at the current position. */static int ins_chars(byte *s, int l){ int n, tl; byte *tbuf = NULL; /* Suppress warning about use-before-set */ /* Move tail of buffer to make space. */ if ((tl = llen - lpos) > 0) { if ((tbuf = driver_alloc(tl)) == NULL) return FALSE; memcpy(tbuf, lc, tl); } n = insert_buf(s, l); if (tl > 0) { memcpy(lc, tbuf, tl); driver_free(tbuf); } llen += n; write_buf(lc - n, llen - lpos + n); move_cursor(llen, lpos); return TRUE;}/* * Delete characters in the buffer. Can delete characters before (n < 0)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?