#include <stdio.h>
#include "obsolete/driver.h"
#include <slang.h>
#include <signal.h>
#if (SLANG_VERSION < 10400 )
#define SLsmg_Char_Type unsigned short
#endif
/* Standard set of integer macros .. */
#define get_int32(s) ((((unsigned char*) (s))[0] << 24) | \
(((unsigned char*) (s))[1] << 16) | \
(((unsigned char*) (s))[2] << 8) | \
(((unsigned char*) (s))[3]))
#define put_int32(i, s) {((char*)(s))[0] = (char)((i) >> 24) & 0xff; \
((char*)(s))[1] = (char)((i) >> 16) & 0xff; \
((char*)(s))[2] = (char)((i) >> 8) & 0xff; \
((char*)(s))[3] = (char)((i) & 0xff);}
#define get_int16(s) ((((unsigned char*) (s))[0] << 8) | \
(((unsigned char*) (s))[1]))
#define put_int16(i, s) {((unsigned char*)(s))[0] = ((i) >> 8) & 0xff; \
((unsigned char*)(s))[1] = (i) & 0xff;}
#define get_int8(s) ((((unsigned char*) (s))[0] ))
#define put_int8(i, s) { ((unsigned char*)(s))[0] = (i) & 0xff;}
#define INIT_TTY 1
#define SET_ABORT_FUNCTION 2
#define GETKEY 3
#define RESET_TTY 4
#define KP_GETKEY 5
#define UNGETKEY 6
#define SETVAR 7
#define GETVAR 8
#define KP_INIT 9
/* screen mgmt */
#define SMG_FILL_REGION 10
#define SMG_SET_CHAR_SET 11
#define SMG_SUSPEND_SMG 12
#define SMG_RESUME_SMG 13
#define SMG_ERASE_EOL 14
#define SMG_GOTORC 15
#define SMG_ERASE_EOS 16
#define SMG_REVERSE_VIDEO 17
#define SMG_SET_COLOR 18
#define SMG_NORMAL_VIDEO 19
#define SMG_PRINTF 20
#define SMG_VPRINTF 21
#define SMG_WRITE_STRING 22
#define SMG_WRITE_NSTRING 23
#define SMG_WRITE_CHAR 24
#define SMG_WRITE_NCHARS 25
#define SMG_WRITE_WRAPPED_STRING 26
#define SMG_CLS 27
#define SMG_REFRESH 28
#define SMG_TOUCH_LINES 29
#define SMG_TOUCH_SCREEN 30
#define SMG_INIT_SMG 31
#define SMG_REINIT_SMG 32
#define SMG_RESET_SMG 33
#define SMG_CHAR_AT 34
#define SMG_SET_SCREEN_START 35
#define SMG_DRAW_HLINE 36
#define SMG_DRAW_VLINE 37
#define SMG_DRAW_OBJECT 38
#define SMG_DRAW_BOX 39
#define SMG_GET_COLUMN 40
#define SMG_GET_ROW 41
#define SMG_FORWARD 42
#define SMG_WRITE_COLOR_CHARS 43
#define SMG_READ_RAW 44
#define SMG_WRITE_RAW 45
#define SMG_SET_COLOR_IN_REGION 46
/* ops for all the tt_ functions */
#define TT_FLUSH_OUTPUT 50
#define TT_SET_SCROLL_REGION 51
#define TT_RESET_SCROLL_REGION 52
#define TT_REVERSE_VIDEO 53
#define TT_BOLD_VIDEO 54
#define TT_BEGIN_INSERT 55
#define TT_END_INSERT 56
#define TT_DEL_EOL 57
#define TT_GOTO_RC 58
#define TT_DELETE_NLINES 59
#define TT_DELETE_CHAR 60
#define TT_ERASE_LINE 61
#define TT_NORMAL_VIDEO 62
#define TT_CLS 63
#define TT_BEEP 64
#define TT_REVERSE_INDEX 65
#define TT_SMART_PUTS 66
#define TT_WRITE_STRING 67
#define TT_PUTCHAR 68
#define TT_INIT_VIDEO 69
#define TT_RESET_VIDEO 70
#define TT_GET_TERMINFO 71
#define TT_GET_SCREEN_SIZE 72
#define TT_SET_CURSOR_VISIBILITY 73
#define TT_SET_MOUSE_MODE 74
#define TT_INITIALIZE 75
#define TT_ENABLE_CURSOR_KEYS 76
#define TT_SET_TERM_VTXXX 77
#define TT_SET_COLOR_ESC 78
#define TT_WIDE_WIDTH 79
#define TT_NARROW_WIDTH 80
#define TT_SET_ALT_CHAR_SET 81
#define TT_WRITE_TO_STATUS_LINE 82
#define TT_DISABLE_STATUS_LINE 83
#define TT_TGETSTR 84
#define TT_TGETNUM 85
#define TT_TGETFLAG 86
#define TT_TIGETENT 87
#define TT_TIGETSTR 88
#define TT_TIGETNUM 89
#define SLTT_GET_COLOR_OBJECT 90
#define TT_SET_COLOR_OBJECT 91
#define TT_SET_COLOR 92
#define TT_SET_MONO 93
#define TT_ADD_COLOR_ATTRIBUTE 94
#define TT_SET_COLOR_FGBG 95
/* aux tty functions */
#define ISATTY 100
#define EFORMAT 101
#define SIGNAL 102
#define SIGNAL_CHECK 103
/* read/write global variables */
#define esl_baud_rate 1
#define esl_read_fd 2
#define esl_abort_char 3
#define esl_ignore_user_abort 4
#define esl_input_buffer_len 5
#define esl_keyboard_quit 6
#define esl_last_key_char 7
#define esl_rl_eof_char 8
#define esl_rline_quit 9
#define esl_screen_rows 10
#define esl_screen_cols 11
#define esl_tab_width 12
#define esl_newline_behaviour 13
#define esl_error 14
#define esl_version 15
#define esl_backspace_moves 16
#define esl_display_eight_bit 17
/* signals */
#define SL_SIGINT 1
#define SL_SIGTSTP 2
#define SL_SIGQUIT 3
#define SL_SIGTTOU 4
#define SL_SIGTTIN 5
#define SL_SIGWINCH 6
static long sl_start();
static int sl_stop(), sl_read();
static struct driver_entry sl_driver_entry;
static int wait_for = 0;
static int signal_cought = 0;
static int sig_to_x(int x)
{
switch (x ) {
case SIGINT: return SL_SIGINT;
case SIGTSTP: return SL_SIGTSTP;
case SIGQUIT: return SL_SIGQUIT;
case SIGTTOU: return SL_SIGTTOU;
case SIGTTIN: return SL_SIGTTIN;
case SIGWINCH: return SL_SIGWINCH;
default: return -1;
}
}
static void sig_handler(int sig)
{
signal_cought = sig_to_x(sig);
}
static int x_to_sig(int x)
{
switch (x ) {
case SL_SIGINT: return SIGINT;
case SL_SIGTSTP: return SIGTSTP;
case SL_SIGQUIT: return SIGQUIT;
case SL_SIGTTOU: return SIGTTOU;
case SL_SIGTTIN: return SIGTTIN;
case SL_SIGWINCH: return SIGWINCH;
default: return -1;
}
}
SLsmg_Char_Type *decode_smg_char_type(char **buf)
{
static SLsmg_Char_Type mbuf[256];
int i;
char *b = *buf;
int len = get_int32(*buf); *buf+=4;
for(i=0; i<len; i++) {
mbuf[i++] = get_int16(*buf); *buf+=2;
}
return mbuf;
}
static long sl_start(long port, char *buf)
{
return port;
}
static int sl_stop(int port)
{
return 1;
}
static int ret_int_int(int port, int i, int j)
{
char buf[9];
buf[0] = 1;
put_int32(i, buf+1);
put_int32(j, buf+5);
driver_output(port, buf, 9);
return i;
}
static int ret_int(int port, int ret)
{
char buf[5];
buf[0] = 1;
put_int32(ret, buf+1);
driver_output(port, buf, 5);
return ret;
}
static int ret_string(int port, char *str)
{
str[-1] = 1;
driver_output(port, str, 1+strlen(str));
return 1;
}
static int sl_output(int port, char *buf, int len)
{
int x,y,z,v,w;
char *str, *t1, *t2, *t3;
int ret;
char ch;
/* check for signals */
if (signal_cought != 0) { /* async out signal */
char xxx[5];
xxx[0] = 0;
put_int32(signal_cought, xxx+1);
driver_output(port, xxx, 5);
signal_cought = 0;
}
switch (*buf++) {
case INIT_TTY: {
int abort_char, flow_ctl, opost;
abort_char = get_int32(buf); buf+=4;
flow_ctl = get_int32(buf); buf+= 4;
opost = get_int32(buf); buf+= 4;
ret = SLang_init_tty (abort_char,flow_ctl, opost);
return ret_int(port, ret);
}
case SET_ABORT_FUNCTION: {
SLang_set_abort_signal (NULL);
return ret_int(port, 0);
}
case GETKEY: {
unsigned int key;
if (SLang_input_pending (0) == 0) {
wait_for = GETKEY;
driver_select(port, 0, DO_READ, 1);
return 0;
}
x = SLang_getkey ();
return ret_int(port, x);
}
/* read a symbol */
case KP_GETKEY: {
if (SLang_input_pending (0) == 0) {
wait_for = KP_GETKEY;
driver_select(port, 0, DO_READ, 1);
return 0;
}
x = SLkp_getkey ();
return ret_int(port, x);
}
case UNGETKEY: {
unsigned char key = (unsigned char) *buf;
SLang_ungetkey (key);
return 0;
}
case RESET_TTY: {
SLang_reset_tty();
return 0;
}
case KP_INIT: {
return ret_int(port, SLkp_init ());
}
case SETVAR: {
x = get_int32(buf);buf+= 4;
y = get_int32(buf);
switch (x) {
case esl_baud_rate:
SLang_TT_Baud_Rate = y; return 0;
case esl_read_fd:
return 0;
case esl_abort_char:
SLang_Abort_Char = y; return 0;
case esl_ignore_user_abort:
SLang_Ignore_User_Abort=y; return 0;
case esl_input_buffer_len :
SLang_Input_Buffer_Len=y; return 0;
case esl_keyboard_quit:
SLKeyBoard_Quit=y; return 0;
case esl_last_key_char:
SLang_Last_Key_Char=y; return 0;
case esl_rl_eof_char:
SLang_RL_EOF_Char=y; return 0;
case esl_rline_quit:
SLang_Rline_Quit=y; return 0;
case esl_screen_rows:
case esl_screen_cols :
return 0;
case esl_tab_width:
SLsmg_Tab_Width=y; return 0;
case esl_newline_behaviour:
SLsmg_Newline_Behavior=y; return 0;
case esl_error:
SLang_Error=y; return 0;
case esl_version:
return 0;
case esl_backspace_moves :
SLsmg_Backspace_Moves=y; return 0;
case esl_display_eight_bit:
SLsmg_Display_Eight_Bit=y; return 0;
default:
return 0;
}
}
case GETVAR: {
x = get_int32(buf);
switch (x) {
case esl_baud_rate:
return ret_int(port, SLang_TT_Baud_Rate);
case esl_read_fd:
return ret_int(port, SLang_TT_Read_FD);
case esl_abort_char:
return (ret_int(port, SLang_Abort_Char));
case esl_ignore_user_abort:
return ret_int(port, SLang_Ignore_User_Abort);
case esl_input_buffer_len :
return ret_int(port, SLang_Input_Buffer_Len);
case esl_keyboard_quit:
return ret_int(port, SLKeyBoard_Quit);
case esl_last_key_char:
return ret_int(port, SLang_Last_Key_Char);
case esl_rl_eof_char:
return ret_int(port, SLang_RL_EOF_Char);
case esl_rline_quit:
return ret_int(port, SLang_Rline_Quit);
case esl_screen_rows:
return ret_int(port, SLtt_Screen_Rows);
case esl_screen_cols :
return ret_int(port, SLtt_Screen_Cols);
case esl_tab_width:
return ret_int(port, SLsmg_Tab_Width);
case esl_newline_behaviour:
return ret_int(port, SLsmg_Newline_Behavior);
case esl_error:
return ret_int(port, SLang_Error);
case esl_version:
return ret_int(port, SLang_Version);
case esl_backspace_moves :
return ret_int(port, SLsmg_Backspace_Moves);
case esl_display_eight_bit:
return ret_int(port, SLsmg_Display_Eight_Bit);
default:
return ret_int(port, -1);
}
}
/*{{{ SLsmg Screen Management Functions */
case SMG_FILL_REGION: {
x = get_int32(buf); buf+= 4;
y = get_int32(buf); buf+= 4;
z = get_int32(buf); buf+= 4;
v = get_int32(buf); buf+= 4;
ch = *buf;
SLsmg_fill_region(x, y,z,v,ch);
return 0;
}
case SMG_SET_CHAR_SET: {
x = get_int32(buf); buf+= 4;
SLsmg_set_char_set(x);
return 0;
}
case SMG_SUSPEND_SMG: {
return ret_int(port, SLsmg_suspend_smg());
}
case SMG_RESUME_SMG: {
ret_int(port, SLsmg_resume_smg());
}
case SMG_ERASE_EOL: {
SLsmg_erase_eol();
return 0;
}
case SMG_GOTORC: {
x = get_int32(buf); buf+= 4;
y = get_int32(buf); buf+= 4;
SLsmg_gotorc(x, y);
return 0;
}
case SMG_ERASE_EOS: {
SLsmg_erase_eos();
return 0;
}
case SMG_REVERSE_VIDEO: {
SLsmg_reverse_video();
return 0;
}
case SMG_SET_COLOR: {
x = get_int32(buf); buf+= 4;
SLsmg_set_color(x);
return 0;
}
case SMG_NORMAL_VIDEO: {
SLsmg_normal_video();
return 0;
}
case SMG_WRITE_STRING: {
SLsmg_write_string(buf);
return 0;
}
case SMG_WRITE_CHAR: {
ch = *buf;
SLsmg_write_char(ch);
return 0;
}
case SMG_WRITE_WRAPPED_STRING: {
t1 = buf;
buf += strlen(t1) + 1;
x = get_int32(buf); buf+= 4;
y = get_int32(buf); buf+= 4;
z = get_int32(buf); buf+= 4;
v = get_int32(buf); buf+= 4;
w = get_int32(buf); buf+= 4;
SLsmg_write_wrapped_string(t1, x,y,z,v,w);
return 0;
}
case SMG_CLS: {
SLsmg_cls();
return 0;
}
case SMG_REFRESH: {
SLsmg_refresh();
return 0;
}
case SMG_TOUCH_LINES: {
x = get_int32(buf); buf+= 4;
y = get_int32(buf); buf+= 4;
SLsmg_touch_lines(x, y);
return 0;
}
case SMG_TOUCH_SCREEN: {
#if (SLANG_VERSION < 10400 )
return ret_int(port, -1);
#else
SLsmg_touch_screen();
#endif
return 0;
}
case SMG_INIT_SMG: {
return ret_int(port, SLsmg_init_smg());
}
case SMG_REINIT_SMG: {
#if (SLANG_VERSION < 10400 )
return ret_int(port, -1);
#else
return ret_int(port, SLsmg_reinit_smg());
#endif
}
case SMG_RESET_SMG: {
SLsmg_reset_smg();
return 0;
}
case SMG_CHAR_AT: {
return ret_int(port, SLsmg_char_at());
}
case SMG_SET_SCREEN_START: {
int *ip1, *ip2;
*ip1 = get_int32(buf); buf+= 4;
*ip2 = get_int32(buf); buf+= 4;
SLsmg_set_screen_start(ip1, ip2);
return ret_int_int(port, *ip1, *ip2);
}
case SMG_DRAW_HLINE: {
x = get_int32(buf); buf+= 4;
SLsmg_draw_hline(x);
return 0;
}
case SMG_DRAW_VLINE: {
x = get_int32(buf); buf+= 4;
SLsmg_draw_vline(x);
return 0;
}
case SMG_DRAW_OBJECT: {
x = get_int32(buf); buf+= 4;
y = get_int32(buf); buf+= 4;
x = get_int32(buf); buf+= 4;
SLsmg_draw_object(x, y,z);
return 0;
}
case SMG_DRAW_BOX: {
x = get_int32(buf); buf+= 4;
y = get_int32(buf); buf+= 4;
z = get_int32(buf); buf+= 4;
v = get_int32(buf); buf+= 4;
SLsmg_draw_box(x, y,z,v);
return 0;
}
case SMG_GET_COLUMN: {
return ret_int(port, SLsmg_get_column());
}
case SMG_GET_ROW: {
return ret_int(port, SLsmg_get_row());
}
case SMG_FORWARD: {
x = get_int32(buf); buf+= 4;
SLsmg_forward(x);
return 0;
}
case SMG_WRITE_COLOR_CHARS: {
SLsmg_Char_Type * sl;
sl = decode_smg_char_type(&buf);
x = get_int32(buf); buf+= 4;
SLsmg_write_color_chars(sl, x);
return 0;
}
case SMG_READ_RAW: {
x = get_int32(buf); buf+= 4;
t1 = malloc((2*x) + 2 + 1);
y = SLsmg_read_raw((unsigned short*)t1 +1, x);
t1[1] = 1;
driver_output(port, t1, y+1);
free(t1);
return 0;
}
case SMG_WRITE_RAW: {
SLsmg_Char_Type * sl;
sl = decode_smg_char_type(&buf);
x = get_int32(buf);
y = SLsmg_write_raw(sl, x);
return ret_int(port, y);
}
case SMG_SET_COLOR_IN_REGION: {
x = get_int32(buf); buf+= 4;
y = get_int32(buf); buf+= 4;
z = get_int32(buf); buf+= 4;
v = get_int32(buf); buf+= 4;
w = get_int32(buf); buf+= 4;
SLsmg_set_color_in_region(x, y,z,v,w);
return 0;
}
/* all the tt_functions */
case TT_FLUSH_OUTPUT: {
ret = SLtt_flush_output();
return ret_int(port, ret);
}
case TT_SET_SCROLL_REGION: {
x = get_int32(buf); buf+=4;
y = get_int32(buf); buf+=4;
SLtt_set_scroll_region(x, y);
return 0;
}
case TT_RESET_SCROLL_REGION: {
SLtt_reset_scroll_region();
return 0;
}
case TT_REVERSE_VIDEO: {
SLtt_reverse_video (get_int32(buf));
return 0;
}
case TT_BOLD_VIDEO: {
SLtt_begin_insert();
return 0;
}
case TT_BEGIN_INSERT: {
SLtt_begin_insert();
return 0;
}
case TT_END_INSERT: {
SLtt_end_insert();
return 0;
}
case TT_DEL_EOL: {
SLtt_del_eol();
return 0;
}
case TT_GOTO_RC: {
x = get_int32(buf); buf+=4;
y = get_int32(buf); buf+=4;
SLtt_goto_rc (x, y);
return 0;
}
case TT_DELETE_NLINES: {
SLtt_delete_nlines(get_int32(buf));
return 0;
}
case TT_DELETE_CHAR: {
SLtt_delete_char();
return 0;
}
case TT_ERASE_LINE: {
SLtt_erase_line();
return 0;
}
case TT_NORMAL_VIDEO: {
SLtt_normal_video();
return 0;
}
case TT_CLS: {
SLtt_cls();
return 0;
}
case TT_BEEP: {
SLtt_beep();
return 0;
}
case TT_REVERSE_INDEX: {
SLtt_reverse_index(get_int32(buf));
return 0;
}
case TT_SMART_PUTS: {
SLsmg_Char_Type *t1 ;
SLsmg_Char_Type *t2;
t1 = decode_smg_char_type(&buf);
t2 = decode_smg_char_type(&buf);
x = get_int32(buf); buf+=4;
y = get_int32(buf); buf+=4;
SLtt_smart_puts(t1, t2,x,y);
return 0;
}
case TT_WRITE_STRING: {
SLtt_write_string (buf);
return 0;
}
case TT_PUTCHAR: {
SLtt_putchar((char) get_int32(buf));
return 0;
}
case TT_INIT_VIDEO: {
ret = SLtt_init_video ();
return ret_int(port, ret);
}
case TT_RESET_VIDEO: {
SLtt_reset_video ();
return 0;
}
case TT_GET_TERMINFO: {
SLtt_get_terminfo();
return 0;
}
case TT_GET_SCREEN_SIZE: {
SLtt_get_screen_size ();
return 0;
}
case TT_SET_CURSOR_VISIBILITY: {
ret = SLtt_set_cursor_visibility (get_int32(buf));
return ret_int(port, ret);
}
case TT_SET_MOUSE_MODE: {
x = get_int32(buf); buf+=4;
y = get_int32(buf); buf+=4;
ret = SLtt_set_mouse_mode (x,y);
return ret_int(port, ret);
}
case TT_INITIALIZE: {
ret =SLtt_initialize (buf);
return ret_int(port, ret);
}
case TT_ENABLE_CURSOR_KEYS: {
SLtt_enable_cursor_keys();
return 0;
}
case TT_SET_TERM_VTXXX: {
return 0;
}
case TT_SET_COLOR_ESC: {
x = get_int32(buf); buf+=4;
SLtt_set_color_esc (x, buf);
return 0;
}
case TT_WIDE_WIDTH: {
SLtt_narrow_width();
return 0;
}
case TT_NARROW_WIDTH: {
SLtt_narrow_width();
return 0;
}
case TT_SET_ALT_CHAR_SET: {
SLtt_set_alt_char_set (get_int32(buf));
return 0;
}
case TT_WRITE_TO_STATUS_LINE: {
x = get_int32(buf); buf+=4;
SLtt_write_to_status_line (buf, x);
return 0;
}
case TT_DISABLE_STATUS_LINE: {
SLtt_disable_status_line ();
return 0;
}
case TT_TGETSTR: {
str = SLtt_tgetstr (buf);
return ret_string(port, str);
}
case TT_TGETNUM: {
x = SLtt_tgetnum (buf);
return ret_int(port, x);
}
case TT_TGETFLAG: {
x = SLtt_tgetflag (buf);
return ret_int(port, x);
}
case TT_TIGETENT: {
str = SLtt_tigetent (buf);
return ret_string(port, str);
}
case TT_TIGETSTR: {
return 0;
}
case TT_TIGETNUM: {
return 0;
}
case SLTT_GET_COLOR_OBJECT: {
x = get_int32(buf); buf+=4;
y = SLtt_get_color_object (x);
return ret_int(port, y);
return 0;
}
case TT_SET_COLOR_OBJECT: {
x = get_int32(buf); buf+=4;
y = get_int32(buf); buf+=4;
SLtt_set_color_object (x, y);
return 0;
}
case TT_SET_COLOR: {
x = get_int32(buf); buf+=4;
t1 = buf;
t2 = buf + (strlen(t1) + 1);
t3 = buf + (strlen(t1) + strlen(t2) + 2);
SLtt_set_color (x, t1, t2, t3);
return 0;
}
case TT_SET_MONO: {
x = get_int32(buf); buf+=4;
t1 = buf;
buf += strlen(t1) + 1;
y = get_int32(buf);
SLtt_set_mono (x, t1, y);
return 0;
}
case TT_ADD_COLOR_ATTRIBUTE: {
x = get_int32(buf); buf+=4;
y = get_int32(buf); buf+=4;
SLtt_add_color_attribute (x, y);
return 0;
}
case TT_SET_COLOR_FGBG: {
x = get_int32(buf); buf+=4;
y = get_int32(buf); buf+=4;
z = get_int32(buf); buf+=4;
SLtt_set_color_fgbg (x, y, z);
return 0;
}
case ISATTY: {
x = get_int32(buf); buf+=4;
return ret_int(port, isatty(x));
}
case EFORMAT: {
fprintf(stderr, "%s", buf);
fflush(stderr);
return 0;
}
case SIGNAL: {
x = get_int32(buf); buf+=4;
SLsignal(x_to_sig(x), sig_handler);
return 0;
}
case SIGNAL_CHECK: {
/* polled */
if (signal_cought != 0)
signal_cought = 0;
return ret_int(port, signal_cought);
}
default:
return 0;
}
}
/* pending getkey request */
sl_ready_input(int port, int fd)
{
unsigned int key;
driver_select(port, 0, DO_READ, 0);
switch (wait_for) {
case GETKEY: {
key = SLang_getkey ();
return ret_int(port, key);
}
case KP_GETKEY: {
key = SLkp_getkey ();
return ret_int(port, key);
}
return 0;
}
}
/*
* Initialize and return a driver entry struct
*/
struct driver_entry *driver_init(void *handle)
{
sl_driver_entry.init = null_func; /* Not used */
sl_driver_entry.start = sl_start;
sl_driver_entry.stop = sl_stop;
sl_driver_entry.output = sl_output;
sl_driver_entry.ready_input = sl_ready_input;
sl_driver_entry.ready_output = null_func;
sl_driver_entry.driver_name = "slang_drv";
sl_driver_entry.finish = null_func;
sl_driver_entry.handle = handle; /* MUST set this!!! */
return &sl_driver_entry;
}
syntax highlighted by Code2HTML, v. 0.9.1