diff options
author | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2011-10-14 04:55:05 +0200 |
---|---|---|
committer | Robin Haberkorn <robin.haberkorn@googlemail.com> | 2011-10-14 04:55:05 +0200 |
commit | 6aa0e0017d7d0cddc006da885946934b06949a91 (patch) | |
tree | 66b688ec32e2f91266db760b1762f2a50cc52036 /libslang/src/slvmstty.c | |
parent | a966db5b71328f6adf9dd767e64b322a3bd7ed9c (diff) | |
download | erlang-slang-fork-6aa0e0017d7d0cddc006da885946934b06949a91.tar.gz |
include libslang-1.4.9 and automatically build it and link erlang-slang against it
few (erlang) people will still have libslang-1.4.9 installed or spend time
to get it to link against the driver
Diffstat (limited to 'libslang/src/slvmstty.c')
-rw-r--r-- | libslang/src/slvmstty.c | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/libslang/src/slvmstty.c b/libslang/src/slvmstty.c new file mode 100644 index 0000000..e22d1ad --- /dev/null +++ b/libslang/src/slvmstty.c @@ -0,0 +1,382 @@ +/* Copyright (c) 1992, 1999, 2001, 2002, 2003 John E. Davis + * This file is part of the S-Lang library. + * + * You may distribute under the terms of either the GNU General Public + * License or the Perl Artistic License. + */ +#include "slinclud.h" + +#include <ssdef.h> +#include <rmsdef.h> +#include <dvidef.h> +#include <jpidef.h> +#include <descrip.h> +#include <iodef.h> +#include <ttdef.h> +#include <tt2def.h> +#include <rms.h> +#include <errno.h> + +#ifdef __DECC +#include <starlet.h> +#include <lib$routines> +#endif + +#include "slang.h" +#include "_slang.h" + +/* If this function returns -1, ^Y will be added to input buffer. */ +int (*SLtty_VMS_Ctrl_Y_Hook) (void); + +typedef struct { /* I/O status block */ + short i_cond; /* Condition value */ + short i_xfer; /* Transfer count */ + long i_info; /* Device information */ +} Iosb_Type; + +typedef struct { /* Terminal characteristics */ + char t_class; /* Terminal class */ + char t_type; /* Terminal type */ + short t_width; /* Terminal width in characters */ + long t_mandl; /* Terminal's mode and length */ + long t_extend; /* Extended terminal characteristics */ +} TermChar_Type; + +static TermChar_Type Old_Term_Char, New_Term_Char; + +/* This serves to identify the channel we are reading input from. */ +static short This_Term; + +typedef struct +{ + short buflen; + short item_code; + int *buf_addr; + int *len_addr; +} item_list_3; + +static int TTY_Inited; + +/* + * Exit Handler Control Block + */ +static struct argument_block + { + int forward_link; + int (*exit_routine)(); + int arg_count; + int *status_address; + int exit_status; + } +exit_block = + { + 0, + NULL, + 1, + &exit_block.exit_status, + 0 + }; + +static void vms_cancel_exithandler() +{ + sys$canexh(exit_block); +} + +static int vms_exit_handler () +{ + if (TTY_Inited == 0) return 0; + SLang_reset_tty (); + return 0; +} + +static int vms_input_buffer; + +static struct vms_ast_iosb +{ + short status; + short offset; + short termlen; + short term; +} vms_ast_iosb; + +static void vms_que_key_ast(); +static int Ast_Fired_Event_Flag; +static int Timer_Event_Flag; +static int Event_Flag_Mask; +static int Ast_Stop_Input; +static int Waiting_For_Ast; + +static int getkey_ast(int not_used) +{ + unsigned int c = 1000; + + if (vms_ast_iosb.offset) + { + c = (unsigned int) vms_input_buffer; + } + + if (c <= 255) + { + if (c == SLang_Abort_Char) + { + if (SLang_Ignore_User_Abort == 0) SLang_Error = SL_USER_BREAK; + SLKeyBoard_Quit = 1; + } + + if ((c != 0x19) /* ^Y */ + || (SLtty_VMS_Ctrl_Y_Hook == NULL) + || (-1 == (*SLtty_VMS_Ctrl_Y_Hook) ())) + { + if (SLang_Input_Buffer_Len < SL_MAX_INPUT_BUFFER_LEN - 3) + SLang_Input_Buffer[SLang_Input_Buffer_Len++] = c; + } + } + + if (Waiting_For_Ast) sys$setef (Ast_Fired_Event_Flag); + Waiting_For_Ast = 0; + vms_que_key_ast(); + return (1); +} + +static void vms_que_key_ast() +{ + static int trmmsk [2] = { 0, 0 }; + int status; + + if (Ast_Stop_Input) return; + status = sys$qio (0, This_Term, + IO$_READVBLK | IO$M_NOECHO | IO$_TTYREADALL, + &vms_ast_iosb, getkey_ast, 1, + &vms_input_buffer, 1, 0, trmmsk, 0, 0); +} + +static char TTY_Name[8]; +static int This_Process_Pid; + +/* FIXME: priority=medium + * The keypad state may have been tampered with by the application. So, I + * need to get the keypad status at initialization time and then reset it + * in the call to SLang_reset_tty. Unfortunately, this will most likely + * involve interaction with the sldisply interface. + */ +int SLang_init_tty (int a, int flow, int out) +{ + Iosb_Type iostatus; + int tmp, name_len, status, lastppid, ppid; + item_list_3 itmlst[3]; + $DESCRIPTOR ( term, TTY_Name); + + itmlst[0].buflen = sizeof(int); + itmlst[0].item_code = JPI$_PID; + itmlst[0].buf_addr = &This_Process_Pid; + itmlst[0].len_addr = &tmp; + + itmlst[1].buflen = 7; + itmlst[1].item_code = JPI$_TERMINAL; + itmlst[1].buf_addr = (int *) TTY_Name; + itmlst[1].len_addr = &name_len; + + itmlst[2].buflen = 0; + itmlst[2].item_code = 0; + itmlst[2].buf_addr = 0; + itmlst[2].len_addr = 0; + + if (a == -1) a = 3; /* ^C */ + SLang_Abort_Char = a; + TTY_Inited = 1; + ppid = 0, lastppid = -1; + + /* Here I get this process pid then I get the master process pid + and use the controlling terminal of that process. */ + while (1) + { + status = sys$getjpiw(0, /* event flag */ + &ppid, /* pid address */ + 0, /* proc name address */ + itmlst, + 0, 0, 0); + + if (status != SS$_NORMAL) + { + fprintf(stderr, "PID: %X, status: %X\n", This_Process_Pid, status); + exit(1); + } + + if (lastppid == ppid) break; + lastppid = ppid; + + itmlst[0].item_code = JPI$_MASTER_PID; + itmlst[0].buf_addr = &ppid; + } + + term.dsc$w_length = name_len; + status = sys$assign ( &term, &This_Term, 0, 0 ); + if (status != SS$_NORMAL) + { + fprintf(stderr,"Unable to assign input channel\n"); + fprintf(stderr,"PID: %X, DEV %s, status: %d\n", This_Process_Pid, TTY_Name, status); + exit(0); + } + + if (NULL == exit_block.exit_routine) + { + exit_block.exit_routine = (int (*)()) vms_exit_handler; + sys$dclexh(&exit_block); + } + + /* allocate an event flag and clear it--- used by ast routines. Since + * I am only using a few local event flags, there is really no need to + * worry about freeing these. + * + * The event flags are used to avoid timing problems with the getkey AST + * as well as for a form of time out. + */ + if (!Ast_Fired_Event_Flag) lib$get_ef (&Ast_Fired_Event_Flag); + sys$clref (Ast_Fired_Event_Flag); + + if (!Timer_Event_Flag) lib$get_ef (&Timer_Event_Flag); + sys$clref (Timer_Event_Flag); + + /* The working assumption here is that the event flags are in the same + * cluster. They need not be but it is very likely that they are. + */ + Event_Flag_Mask = ((unsigned) 1 << (Ast_Fired_Event_Flag % 32)); + Event_Flag_Mask |= ((unsigned) 1 << (Timer_Event_Flag % 32)); + + Waiting_For_Ast = 0; + Ast_Stop_Input = 0; + + /* Get the startup terminal characteristics */ + status = sys$qiow(0, /* Wait on event flag zero */ + This_Term, /* Channel to input terminal */ + IO$_SENSEMODE, /* Get current characteristic */ + &iostatus, /* Status after operation */ + 0, 0, /* No AST service */ + &Old_Term_Char, /* Terminal characteristics buf */ + sizeof(Old_Term_Char),/* Size of the buffer */ + 0, 0, 0, 0); + + New_Term_Char = Old_Term_Char; + New_Term_Char.t_mandl |= TT$M_EIGHTBIT | TT$M_NOECHO; + New_Term_Char.t_extend |= TT2$M_PASTHRU | TT2$M_XON; + + status = sys$qiow(0, /* Wait on event flag zero */ + This_Term, /* Channel to input terminal */ + IO$_SETMODE, /* Set current characteristic */ + &iostatus, /* Status after operation */ + 0, 0, /* No AST service */ + &New_Term_Char, /* Terminal characteristics buf */ + sizeof(New_Term_Char),/* Size of the buffer */ + 0, 0, 0, 0); + + vms_que_key_ast(); /* set up the key ast */ + return 0; +} + +static void cancel_ast (void) +{ + if (TTY_Inited == 0) return; + + /* stop the keyboard ast */ + sys$setast (0); /* disable AST delivery */ + sys$clref (Ast_Fired_Event_Flag); + Waiting_For_Ast = 1; + Ast_Stop_Input = 1; + + /* cancel all i/o on this channel. This canels pending, as well as those + * already in progress and queued. In particular, according to the + * manuals, cancelling I/O on the channel will cause the getkey AST + * to fire even though the sys$qio call was aborted. This is crucial + * because below we wait for the AST to set the event flag. + */ + sys$cancel (This_Term); + sys$setast (1); /* enable ASTs again */ + sys$waitfr (Ast_Fired_Event_Flag); /* sleep until it fires */ + Waiting_For_Ast = 0; +} + +void SLang_reset_tty (void) +{ + Iosb_Type iostatus; + + if (!TTY_Inited) return; + + cancel_ast (); + TTY_Inited = 0; + + /* reset the terminal characteristics */ + + sys$qiow(0, /* event flag 0 */ + This_Term, /* Channel to input terminal */ + IO$_SETMODE, /* Set current characteristic */ + &iostatus, /* Status after operation */ + 0, 0, /* No AST service */ + &Old_Term_Char, /* Terminal characteristics buf */ + sizeof(Old_Term_Char), /* Size of the buffer */ + 0, 0, 0, 0); /* unused */ + +} + +unsigned int _SLsys_getkey() +{ + unsigned int c; + + if (SLKeyBoard_Quit) return((unsigned int) SLang_Abort_Char); + + /* On VMS, the keyboard ast routine should be stuffing the buffer, so + do nothing except sleep */ + + /* clear the flag which ast will set */ + Waiting_For_Ast = 0; + + if (SLang_Input_Buffer_Len) return(SLang_getkey()); + while (!_SLsys_input_pending(450)); + c = SLang_getkey(); + return(c); +} + +/* waits *secs tenth of seconds for input */ +int _SLsys_input_pending(int tsecs) +{ + unsigned long daytim[2]; + + if (SLang_Input_Buffer_Len) return(SLang_Input_Buffer_Len); + + if (tsecs < 0) + tsecs = -tsecs/100; /* tsecs is ms, convert to 1/10 sec */ + + if (tsecs) + { + /* takes a quad word time. If negative, use a relative time. */ + daytim[1] = 0xFFFFFFFF; + daytim[0] = -(tsecs * 1000 * 1000); + /* 1000 * 1000 is a tenth of a sec */ + + sys$clref (Ast_Fired_Event_Flag); + /* sys$clref (Timer_Event_Flag); sys$setimr call clears this */ + + /* set up a flag for the ast so it knows to set the event flag */ + Waiting_For_Ast = 1; + + sys$setimr(Timer_Event_Flag, daytim, 0, 1); + + /* this will return when ast does its job or timer expires. + * The first argument simply serves to identify the cluster for + * the event flag and that is all. The second argument serves + * to identify the event flags to wait for. + */ + sys$wflor (Ast_Fired_Event_Flag, Event_Flag_Mask); + + Waiting_For_Ast = 0; + + /* cancel the timer */ + sys$cantim(1, 3); /* 3 is user mode */ + } + return (SLang_Input_Buffer_Len); +} + +int SLang_set_abort_signal (void (*f)(int)) +{ + return 0; +} + |