ttsl_drv.c
来自「OTP是开放电信平台的简称」· C语言 代码 · 共 457 行
C
457 行
/* ``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. */#include "sys.h"#include <ctype.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <signal.h>#include "erl_driver.h"#define TRUE 1#define FALSE 0static int cols; /* Number of columns available. */static int rows; /* Number of rows available. *//* 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)#define ISPRINT(c) (isprint(c) || (128+32 <= (c) && (c) < 256))/* * XXX These are used by win_con.c (for command history). * Should be cleaned up. */byte *lbuf; /* The current line buffer */int llen; /* The current line length */byte *lc; /* The current character pointer */int lpos;#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 *s);static ErlDrvPort ttysl_port;extern ErlDrvEvent console_input_event;extern HANDLE console_thread;static HANDLE ttysl_in = INVALID_HANDLE_VALUE; /* Handle for console input. */static HANDLE ttysl_out = INVALID_HANDLE_VALUE; /* Handle for console output *//* Functions that work on the line buffer. */static int start_lbuf();static int stop_lbuf();static int put_chars();static int move_rel();static int ins_chars();static int del_chars();static byte *step_over_chars(int n);static int insert_buf();static int write_buf();static void move_cursor(int, 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", NULL, NULL, NULL, NULL};static int ttysl_init(){ lbuf = NULL; /* For line buffer handling */ ttysl_port = (ErlDrvPort)-1; return TRUE;}static ErlDrvData ttysl_start(ErlDrvPort port, char* buf){ if ((int)ttysl_port != -1 || console_thread == NULL) { return ERL_DRV_ERROR_GENERAL; } start_lbuf(); driver_select(port, console_input_event, DO_READ, 1); ttysl_port = port; return (ErlDrvData)ttysl_port;/* Nothing important to return */}static void ttysl_stop(ErlDrvData ttysl_data){ if ((int)ttysl_port != -1) { driver_select(ttysl_port, console_input_event, DO_READ, 0); } ttysl_in = ttysl_out = INVALID_HANDLE_VALUE; stop_lbuf(); ttysl_port = (ErlDrvPort)-1;}/* * Check that there is enough room in all buffers to copy all pad chars * and stuff we need. If not, realloc lbuf. */static int check_buf_size(s,n)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 = 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("\n", 1); if (check_buf_size(buf+1, count-1) == 0) return; switch (buf[0]) { case OP_PUTC: put_chars(buf+1, count-1); break; case OP_MOVE: move_rel(get_sint16(buf+1)); break; case OP_INSC: ins_chars(buf+1, count-1); break; case OP_DELC: del_chars(get_sint16(buf+1)); break; case OP_BEEP: ConBeep(); break; default: /* Unknown op, just ignore. */ break; } return;}extern int read_inbuf(char *data, int n);static void ttysl_from_tty(ErlDrvData ttysl_data, ErlDrvEvent fd){ char inbuf[64]; driver_output(ttysl_port, inbuf, ConReadInput(inbuf,1)); }/* * Gets signed 16 bit integer from binary buffer. */static Sint16get_sint16(char *s){ return ((*s << 8) | ((byte*)s)[1]);}static int start_lbuf(void){ if (!lbuf && !(lbuf = (byte*) malloc(lbuf_size))) return FALSE; llen = 0; lc = lbuf; lpos = 0; return TRUE;}static int stop_lbuf(){ if (lbuf) free(lbuf); lbuf = NULL; return TRUE;}/* Put l characters from s into the buffer and output them. */static int put_chars(s, l)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(n)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(s, l)byte *s;int l;{ int n, tl; byte *tbuf; /* Move tail of buffer to make space. */ if ((tl = llen - lpos) > 0) { if ((tbuf = malloc(tl)) == NULL) return FALSE; memcpy(tbuf, lc, tl); } n = insert_buf(s, l); if (tl > 0) { memcpy(lc, tbuf, tl); 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) * and after (n > 0) the current position. Cursor left at beginning of * deleted block. */static int del_chars(n)int n;{ int i, l, r; byte *c; /* Step forward or backwards over n logical characters. */ c = step_over_chars(n); if (c > lc) { l = c - lc; /* Buffer characters to delete */ r = llen - lpos - l; /* Characters after deleted */ /* Fix up buffer and buffer pointers. */ if (r > 0) memcpy(lc, c, r); llen -= l; /* Write out characters after, blank the tail and jump back to lpos. */ write_buf(lc, r); for (i = l ; i > 0; --i) ConPutChar(' '); move_cursor(llen + l, lpos); } else if (c < lc) { l = lc - c; /* Buffer characters */ r = llen - lpos; /* Characters after deleted */ move_cursor(lpos, lpos-l); /* Move back */ /* Fix up buffer and buffer pointers. */ if (r > 0) memcpy(c, lc, r); lc = c; lpos -= l; llen -= l; /* Write out characters after, blank the tail and jump back to lpos. */ write_buf(lc, r); for (i = l ; i > 0; --i) ConPutChar(' '); move_cursor(llen + l, lpos); } return TRUE;}/* Step over n logical characters, check for overflow. */static byte *step_over_chars(n)int n;{ byte *c, *beg, *end; beg = lbuf; end = lbuf + llen; c = lc; for ( ; n > 0 && c < end; --n) { c++; while (c < end && *c == PAD) c++; } for ( ; n < 0 && c > beg; n++) { --c; while (c > beg && *c == PAD ) --c; } return c;}/* * Insert n characters into the buffer at lc. Update pointers into buffer. * Know about pad characters and treat \n specially. */static int insert_buf(byte* s, int n){ int pos; byte *start; /* Copy the string to lbuf expanding control characters. */ for (pos = lpos, start = lc; n > 0; --n, s++) { if (ISPRINT(*s)) { *lc++ = *s; pos++; } else if (*s == '\t') { *lc++ = '\t'; for (pos++; pos % 8; pos++) *lc++ = PAD; } else if (*s == '\n' || *s == '\r') { write_buf(start, lc - start); ConPutChar('\r'); if (*s == '\n') ConPutChar('\n'); if (llen > pos) memcpy(lbuf, lc, llen - pos);
lc = start = lbuf; llen = lpos = pos = 0; } else if (*s >= 128) { /* "Meta" characters printed as \nnn */ *lc++ = *s; *lc++ = PAD; *lc++ = PAD; *lc++ = PAD; pos += 4; } else { *lc++ = *s; *lc++ = PAD; pos += 2; } } lpos = pos; return lc - start; /* Return characters written */}/* * Write n characters in line buffer starting at s. Be smart about * non-printables. Know about pad characters and that \n can never * occur normally. */static int write_buf(s, n)byte *s;int n;{ while (n > 0) { if (ISPRINT(*s)) { ConPutChar(*s); --n; s++; } else if (*s == '\t') { do { ConPutChar(' '); --n; s++; } while (*s == PAD); } else if (*s >= 128) { ConPutChar('\\'); ConPutChar(((*s >> 6) & 07) + '0'); ConPutChar(((*s >> 3) & 07) + '0'); ConPutChar(((*s >> 0) & 07) + '0'); n -= 4; s += 4; } else { ConPutChar('^'); ConPutChar(*s == 0177 ? '?' : *s | 0x40); n -= 2; s += 2; } } return TRUE;}static voidmove_cursor(int from, int to){ ConSetCursor(from,to);}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?