This is vms.c in view mode; [Download] [Up]
/* * Advanced VMS terminal driver * * Consults the system's terminal tables for both DEC terminals, * foreign and user defined terminals. * * Author: Curtis Smith * Update history: * 14-Jul-1987, first revision. * 02-Jan-1988, by J. A. Lomicka: Code addition for interpreting * LK201 function keys, application keypad and cursor * position reports. * 09-Apr-1988, second revision. * Major changes: * 1) H files removed; replaced with globalvalues. * 2) Terminal now left in ECHO mode. Read call * disables echo. * 3) TYPAHD macro now performs correctly. * 4) $sres variable now accepts NORMAL and WIDE. * 5) Writes to screen now use QIO without waiting. * This gives a slight increase in performance. * Had to make some QIOW a different event flag number. * 6) Function keys, special keys and arrow keys * are now bound using the following table: * FNa-DOWN FNn-5 FN0- FNA-F10 FNN-E1 * FNb-LEFT FNo-6 FN1-F1 FNB-F11 FNO-E2 * FNc-RITE FNp-7 FN2-F2 FNC-F12 FNP-E3 * FNd-UP FNq-8 FN3-F3 FND-F13 FNQ-E4 * FNe-PF1 FNr-9 FN4-F4 FNE-F14 FNR-E5 * FNf-PF2 FNs-. FN5-F5 FNF-F15 FNS-E6 * FNg-PF3 FNt-ENT FN6-F6 FNG-F16 FNT- * FNh-PF4 FNu-, FN7-F7 FNH-F17 FNU- * FNi-0 FNv-- FN8-F8 FNI-F18 FNV- * FNj-1 FNw- FN9-F9 FNJ-F19 FNW- * FNk-2 FNx- FNK-F20 FNX- * FNl-3 FNy- FNL- FNY- * FNm-4 FNz- FNM- FNZ- * See ebind.h for key bindings. * 2-dec-88 Curtis Smith * - These have been rebound to the new machine independant bindings */ /** Standard include files **/ #include <stdio.h> /* Standard I/O package */ #include "estruct.h" /* Emacs' structures */ #include "etype.h" #include "edef.h" /* Emacs' definitions */ #include "elang.h" #if VMS /*** * nothing - The nothing function. * * This function is used as a placeholder for unimplemented functions, * or to compile an empty module (which VMS doesn't like). * * Nothing returned. ***/ nothing() { /* Nothing */ } #if VMSVT /** Parameters **/ #define NKEYENT 128 /* Number of keymap entries */ /** VMS's include files **/ #include <descrip.h> /* Descriptor definitions */ /** VMS's global values **/ globalvalue IO$M_NOECHO; /* Suppress echo on read */ globalvalue IO$M_NOFORMAT; /* Suppress formatting on write */ globalvalue IO$M_TIMED; /* Timeout on input */ globalvalue IO$M_TYPEAHDCNT; /* Get typeahead count */ globalvalue IO$_READLBLK; /* Read logical block */ globalvalue IO$_SENSEMODE; /* Sense mode of terminal */ globalvalue IO$_SETMODE; /* Set mode of terminal */ globalvalue IO$_WRITELBLK; /* Write logical block */ globalvalue SMG$K_BEGIN_REVERSE; /* Begin reverse video */ globalvalue SMG$K_COLUMNS; /* Number of columns narrow */ globalvalue SMG$K_END_REVERSE; /* End reverse video */ globalvalue SMG$K_ERASE_TO_END_LINE; /* Erase to end of line */ globalvalue SMG$K_ERASE_WHOLE_DISPLAY; /* Erase entire screen */ globalvalue SMG$K_KEY_0; /* 0 key */ globalvalue SMG$K_KEY_1; /* 1 key */ globalvalue SMG$K_KEY_2; /* 2 key */ globalvalue SMG$K_KEY_3; /* 3 key */ globalvalue SMG$K_KEY_4; /* 4 key */ globalvalue SMG$K_KEY_5; /* 5 key */ globalvalue SMG$K_KEY_6; /* 6 key */ globalvalue SMG$K_KEY_7; /* 7 key */ globalvalue SMG$K_KEY_8; /* 8 key */ globalvalue SMG$K_KEY_9; /* 9 key */ globalvalue SMG$K_KEY_COMMA; /* Comma key */ globalvalue SMG$K_KEY_DOWN_ARROW; /* Down arrow key */ globalvalue SMG$K_KEY_ENTER; /* Enter key */ globalvalue SMG$K_KEY_E1; /* E1 key */ globalvalue SMG$K_KEY_E2; /* E2 key */ globalvalue SMG$K_KEY_E3; /* E3 key */ globalvalue SMG$K_KEY_E4; /* E4 key */ globalvalue SMG$K_KEY_E5; /* E5 key */ globalvalue SMG$K_KEY_E6; /* E6 key */ globalvalue SMG$K_KEY_F1; /* F1 key */ globalvalue SMG$K_KEY_F2; /* F2 key */ globalvalue SMG$K_KEY_F3; /* F3 key */ globalvalue SMG$K_KEY_F4; /* F4 key */ globalvalue SMG$K_KEY_F5; /* F5 key */ globalvalue SMG$K_KEY_F6; /* F6 key */ globalvalue SMG$K_KEY_F7; /* F7 key */ globalvalue SMG$K_KEY_F8; /* F8 key */ globalvalue SMG$K_KEY_F9; /* F9 key */ globalvalue SMG$K_KEY_F10; /* F10 key */ globalvalue SMG$K_KEY_F11; /* F11 key */ globalvalue SMG$K_KEY_F12; /* F12 key */ globalvalue SMG$K_KEY_F13; /* F13 key */ globalvalue SMG$K_KEY_F14; /* F14 key */ globalvalue SMG$K_KEY_F15; /* F15 key */ globalvalue SMG$K_KEY_F16; /* F16 key */ globalvalue SMG$K_KEY_F17; /* F17 key */ globalvalue SMG$K_KEY_F18; /* F18 key */ globalvalue SMG$K_KEY_F19; /* F19 key */ globalvalue SMG$K_KEY_F20; /* F20 key */ globalvalue SMG$K_KEY_LEFT_ARROW; /* Left arrow key */ globalvalue SMG$K_KEY_MINUS; /* Minus key */ globalvalue SMG$K_KEY_PERIOD; /* Period key */ globalvalue SMG$K_KEY_PF1; /* PF1 key */ globalvalue SMG$K_KEY_PF2; /* PF2 key */ globalvalue SMG$K_KEY_PF3; /* PF3 key */ globalvalue SMG$K_KEY_PF4; /* PF4 key */ globalvalue SMG$K_KEY_RIGHT_ARROW; /* Right arrow key */ globalvalue SMG$K_KEY_UP_ARROW; /* Up arrow key */ globalvalue SMG$K_SET_CURSOR_ABS; /* Set cursor */ globalvalue SMG$K_WIDE_SCREEN_COLUMNS; /* Number of columns wide */ globalvalue SMG$K_WIDTH_NARROW; /* Set terminal to narrow mode */ globalvalue SMG$K_WIDTH_WIDE; /* Set terminal to wide mode */ globalvalue SS$_TIMEOUT; /* Status if read timed-out */ globalvalue TT2$M_PASTHRU; /* Passthru mode in t_extend */ /** I/O information block definitions **/ struct iosb { /* I/O status block */ short i_cond; /* Condition value */ short i_xfer; /* Transfer count */ long i_info; /* Device information */ }; struct termchar { /* 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 characteristics */ }; struct tahd { /* Typeahead count */ short t_count; /* Number of character waiting */ char t_first; /* Next character available */ char t_resv1; /* Reserved by DEC */ long t_resv2; /* Reserved by DEC */ }; /** Type definitions **/ struct keyent { /* Key mapping entry */ struct keyent * samlvl; /* Character on same level */ struct keyent * nxtlvl; /* Character on next level */ char ch; /* Character */ int code; /* Resulting keycode */ }; /** Command success **/ #define SUCCESS(x) ((x)&1) /* TRUE if successful */ #define FAILURE(x) (((x)&1)==0) /* TRUE if unsuccessful */ /** Values to manage the screen **/ static int termtype; /* Handle to pass to SMG */ static short channel; /* Terminal I/O channel */ static struct termchar oldmode; /* Old terminal modes */ static struct termchar newmode; /* New terminal modes */ static char * begin_reverse; /* Begin reverse video */ static char * end_reverse; /* End reverse video */ static char * erase_to_end_line; /* Erase to end of line */ static char * erase_whole_display; /* Erase whole display */ static char * width_narrow; /* Set narrow size screen */ static char * width_wide; /* Set wide size screen */ static int narrow_char; /* Number of characters narrow */ static int wide_char; /* Number of characters wide */ static char inbuf[64]; /* Input buffer */ static char * inbufh = inbuf; /* Head of input buffer */ static char * inbuft = inbuf; /* Tail of input buffer */ static char outbuf[1024]; /* Output buffer */ static char * outbuft = outbuf; /* Tail of output buffer */ static char keyseq[256]; /* Prefix escape sequence table */ static struct keyent keymap[NKEYENT]; /* Key map */ static struct keyent * nxtkey = keymap; /* Next free key entry */ /** Forward references **/ int vmsopen(), vmsclose(), vmsgetc(), vmsputc(), vmsflush(); int vmsmove(), vmseeol(), vmseeop(), vmsbeep(), vmsrev(), vmscres(); /** Terminal dispatch table **/ TERM term = { 72 - 1, /* Max number of rows allowable */ /* Filled in */ - 1, /* Current number of rows used */ 160, /* Max number of columns */ /* Filled in */ 0, /* Current number of columns */ 64, /* Min margin for extended lines*/ 8, /* Size of scroll region */ 100, /* # times thru update to pause */ vmsopen, /* Open terminal at the start */ vmsclose, /* Close terminal at end */ nothing, /* Open keyboard */ nothing, /* Close keyboard */ vmsgetc, /* Get character from keyboard */ vmsputc, /* Put character to display */ vmsflush, /* Flush output buffers */ vmsmove, /* Move cursor, origin 0 */ vmseeol, /* Erase to end of line */ vmseeop, /* Erase to end of page */ vmsbeep, /* Beep */ vmsrev, /* Set reverse video state */ vmscres /* Change screen resolution */ #if COLOR , nothing, /* Set forground color */ nothing /* Set background color */ #endif /* COLOR */ }; /*** * vmsmove - Move the cursor (0 origin) * * vmsmove calls to the SMG run-time library to produce a character * sequence to position the cursor. If the sequence cannot be made, * a string "OOPS" is produced instead, much like the termcap library * under UNIX. In the case of "OOPS", the user will soon know that * his terminal entry is incorrect. * * Nothing returned. ***/ vmsmove(row, column) int row; /* Row position */ int column; /* Column position */ { char buffer[32]; int rlen, status; static int code = SMG$K_SET_CURSOR_ABS; static int len = sizeof(buffer); static int arg[3] = { 2 }; /* SMG assumes the row/column positions are 1 based. */ arg[1] = row + 1; arg[2] = column + 1; /* Call to SMG for the sequence */ status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer, arg); if (SUCCESS(status)) { buffer[rlen] = '\0'; vmsputs(buffer); } else vmsputs("OOPS"); } /*** * vmscres - Change screen resolution * * vmscres changes the screen resolution of the current window. * Allowable sizes are NORMAL and WIDE. * * Nothing returned ***/ vmscres(value) char * value; /* Value to set */ { int width; /* Skip if not supported */ if (width_wide == NULL || width_narrow == NULL) return; /* Check value */ if (strcmp(value, "WIDE") == 0) { width = wide_char; vmsputs(width_wide); } else if (strcmp(value, "NORMAL") == 0) { width = narrow_char; vmsputs(width_narrow); } /* Change width */ oldmode.t_width = newmode.t_width = width; newwidth(TRUE, width); /* Set resolution variable */ strcpy(sres, value); } /*** * vmsrev - Set the reverse video status * * vmsrev either sets or resets the reverse video state, based on the * boolean argument. This function is only called if the revexist * boolean variable is set to TRUE. Otherwise there is no reverse * video available. * * Nothing returned. ***/ vmsrev(status) int status; /* TRUE if setting reverse */ { vmsputs(status ? begin_reverse : end_reverse); } /*** * vmseeol - Erase to end of line * * When this function is called, the lines worth of text after the * cursor is erased. This function is only called if the eolexist * boolean variable is set to TRUE. Otherwise the display manager * will produce enough spaces to erase the line. * * Nothing returned. ***/ vmseeol() { vmsputs(erase_to_end_line); } /*** * vmseeop - Erase to end of page (clear screen) * * vmseeop really should be called vmsclear because it really should * be an erase screen function. When called, this routine will send * the erase entire screen sequence to the output. * * Nothing returned. ***/ vmseeop() { vmsputs(erase_whole_display); } /*** * vmsbeep - Ring the bell * * vmsbeep send a bell character to the output. It might be possible * in the future to include the NOISY definition and attempt to flash * the screen, perhaps using LIGHT_SCREEN and DARK_SCREEN. * * Nothing returned. ***/ vmsbeep() { vmsputc('\007'); } /*** * vmsgetstr - Get an SMG string capability by name * * vmsgetstr attempts to obtain the escape sequence for a particular * job from the SMG library. Most sequences do not require a parameter * with the sequence, others do. In order to obtain the definition * without knowing ahead of time whether ornot the definition has a * parameter, we call SMG once with a parameter and if that fails, we * try again without one. If both attempts fail, we will return the * NULL string. * * Storage for the sequence comes from a local pool. * * Returns: Escape sequence * NULL No escape sequence available ***/ char * vmsgetstr(code) int code; /* Request code */ { char * result; int rlen, status; static char seq[1024]; static char * buffer = seq; static int len = sizeof(seq); static int arg[2] = { 1, 1 }; /* Get sequence with one parameter */ status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer, arg); if (FAILURE(status)) { /* Try again with zero parameters */ status = SMG$GET_TERM_DATA(&termtype, &code, &len, &rlen, buffer); if (FAILURE(status)) return NULL; } /* Check for empty result */ if (rlen == 0) return NULL; /* Save current position so we can return it to caller */ result = buffer; buffer[rlen++] = '\0'; buffer += rlen; /* Return capability to user */ return result; } /*** * vmsgetnum - Get numerical constant from SMG * * vmsgetnum attempts to get a numerical constant from the SMG package. * If the constant cannot be found, -1 is returned. ***/ int vmsgetnum(code) int code; /* SMG code */ { int status, result; /* Call SMG for code translation */ status = SMG$GET_NUMERIC_DATA(&termtype, &code, &result); return FAILURE(status) ? -1 : result; } /*** * vmsaddkey - Add key to key map * * vmsaddkey adds a new escape sequence to the sequence table. * I am not going to try to explain this table to you in detail. * However, in short, it creates a tree which can easily be transversed * to see if input is in a sequence which can be translated to a * function key (arrows and find/select/do etc. are treated like * function keys). If the sequence is ambiguous or duplicated, * it is silently ignored. * * Nothing returned ***/ vmsaddkey(code, fn) int code; /* SMG key code */ int fn; /* Resulting keycode */ { char * seq; int first; struct keyent * cur, * nxtcur; /* Skip on NULL sequence */ seq = vmsgetstr(code); if (seq == NULL) return; /* If no keys defined, go directly to insert mode */ first = 1; if (nxtkey != keymap) { /* Start at top of key map */ cur = keymap; /* Loop until matches exhast */ while (*seq) { /* Do we match current character */ if (*seq == cur->ch) { /* Advance to next level */ seq++; cur = cur->nxtlvl; first = 0; } else { /* Try next character on same level */ nxtcur = cur->samlvl; /* Stop if no more */ if (nxtcur) cur = nxtcur; else break; } } } /* Check for room in keymap */ if (strlen(seq) > NKEYENT - (nxtkey - keymap)) return; /* If first character if sequence is inserted, add to prefix table */ if (first) keyseq[(unsigned char) *seq] = 1; /* If characters are left over, insert them into list */ for (first = 1; *seq; first = 0) { /* Make new entry */ nxtkey->ch = *seq++; nxtkey->code = fn; /* If root, nothing to do */ if (nxtkey != keymap) { /* Set first to samlvl, others to nxtlvl */ if (first) cur->samlvl = nxtkey; else cur->nxtlvl = nxtkey; } /* Advance to next key */ cur = nxtkey++; } } /*** * vmscap - Get capabilities from VMS's SMG library * * vmscap retrives all the necessary capabilities from the SMG * library to operate microEmacs. If an insufficent number of * capabilities are found for the particular terminal, an error * status is returned. * * Returns: 0 if okay, <>0 if error ***/ int vmscap() { char * set_cursor_abs; int status; /* Start SMG package */ status = SMG$INIT_TERM_TABLE_BY_TYPE(&oldmode.t_type, &termtype); if (FAILURE(status)) { printf(TEXT189); /* "Cannot find entry for terminal type.\n" */ printf(TEXT190); /* "Check terminal type with \"SHOW TERMINAL\" or\n" */ printf(TEXT191); /* "try setting with \"SET TERMINAL/INQUIRE\"\n" */ return 1; } /* Get reverse video */ begin_reverse = vmsgetstr(SMG$K_BEGIN_REVERSE); end_reverse = vmsgetstr(SMG$K_END_REVERSE); revexist = begin_reverse != NULL && end_reverse != NULL; /* Get erase to end of line */ erase_to_end_line = vmsgetstr(SMG$K_ERASE_TO_END_LINE); eolexist = erase_to_end_line != NULL; /* Get more neat stuff */ erase_whole_display = vmsgetstr(SMG$K_ERASE_WHOLE_DISPLAY); width_wide = vmsgetstr(SMG$K_WIDTH_WIDE); width_narrow = vmsgetstr(SMG$K_WIDTH_NARROW); narrow_char = vmsgetnum(SMG$K_COLUMNS); wide_char = vmsgetnum(SMG$K_WIDE_SCREEN_COLUMNS); set_cursor_abs = vmsgetstr(SMG$K_SET_CURSOR_ABS); /* Disable resoultion if unreasonable */ if (narrow_char < 10 || wide_char < 10) { width_wide = width_narrow = NULL; strcpy(sres, "NORMAL"); } else /* Kludge resolution */ strcpy(sres, oldmode.t_width == wide_char ? "WIDE" : "NORMAL"); /* Check for minimal operations */ if (set_cursor_abs == NULL || erase_whole_display == NULL) { printf(TEXT192); /* "The terminal type does not have enough power to run\n" */ printf(TEXT193); /* "MicroEMACS. Try a different terminal or check\n" */ printf(TEXT194); /* "type with \"SHOW TERMINAL\".\n" */ return 1; } /* Add function keys to keymapping table */ vmsaddkey(SMG$K_KEY_DOWN_ARROW, 'N'); vmsaddkey(SMG$K_KEY_LEFT_ARROW, 'B'); vmsaddkey(SMG$K_KEY_RIGHT_ARROW, 'F'); vmsaddkey(SMG$K_KEY_UP_ARROW, 'P'); vmsaddkey(SMG$K_KEY_PF1, '1'); vmsaddkey(SMG$K_KEY_PF2, '2'); vmsaddkey(SMG$K_KEY_PF3, '3'); vmsaddkey(SMG$K_KEY_PF4, '4'); vmsaddkey(SMG$K_KEY_0, ALTD | '0'); vmsaddkey(SMG$K_KEY_1, ALTD | '1'); vmsaddkey(SMG$K_KEY_2, ALTD | '2'); vmsaddkey(SMG$K_KEY_3, ALTD | '3'); vmsaddkey(SMG$K_KEY_4, ALTD | '4'); vmsaddkey(SMG$K_KEY_5, ALTD | '5'); vmsaddkey(SMG$K_KEY_6, ALTD | '6'); vmsaddkey(SMG$K_KEY_7, ALTD | '7'); vmsaddkey(SMG$K_KEY_8, ALTD | '8'); vmsaddkey(SMG$K_KEY_9, ALTD | '9'); vmsaddkey(SMG$K_KEY_PERIOD, SHFT|'.'); vmsaddkey(SMG$K_KEY_ENTER, SHFT|CTRL|'M'); vmsaddkey(SMG$K_KEY_COMMA, SHFT|','); vmsaddkey(SMG$K_KEY_MINUS, SHFT|'-'); vmsaddkey(SMG$K_KEY_F1, '1'); vmsaddkey(SMG$K_KEY_F2, '2'); vmsaddkey(SMG$K_KEY_F3, '3'); vmsaddkey(SMG$K_KEY_F4, '4'); vmsaddkey(SMG$K_KEY_F5, '5'); vmsaddkey(SMG$K_KEY_F6, '6'); vmsaddkey(SMG$K_KEY_F7, '7'); vmsaddkey(SMG$K_KEY_F8, '8'); vmsaddkey(SMG$K_KEY_F9, '9'); vmsaddkey(SMG$K_KEY_F10, '0'); vmsaddkey(SMG$K_KEY_F11, SHFT | '1'); vmsaddkey(SMG$K_KEY_F12, SHFT | '2'); vmsaddkey(SMG$K_KEY_F13, SHFT | '3'); vmsaddkey(SMG$K_KEY_F14, SHFT | '4'); vmsaddkey(SMG$K_KEY_F15, SHFT | '5'); vmsaddkey(SMG$K_KEY_F16, SHFT | '6'); vmsaddkey(SMG$K_KEY_F17, SHFT | '7'); vmsaddkey(SMG$K_KEY_F18, SHFT | '8'); vmsaddkey(SMG$K_KEY_F19, SHFT | '9'); vmsaddkey(SMG$K_KEY_F20, SHFT | '0'); vmsaddkey(SMG$K_KEY_E1, CTRL | 'S'); vmsaddkey(SMG$K_KEY_E2, 'C'); vmsaddkey(SMG$K_KEY_E3, 'D'); vmsaddkey(SMG$K_KEY_E4, ALTD | 'S'); vmsaddkey(SMG$K_KEY_E5, 'Z'); vmsaddkey(SMG$K_KEY_E6, 'V'); /* Everything okay */ return 0; } /*** * vmsgtty - Get terminal type from system control block * * vmsgtty obtains the terminal's information such as flags modes, * baud rate, size etc. and stores it in the structure block. * If the block cannot be obtainedm, an error condition is returned. * * Returns: Status ***/ int vmsgtty(tc) struct termchar * tc; /* Terminal characteristics */ { int status; struct iosb io; /* Get terminal characteristics */ status = SYS$QIOW(1, channel, IO$_SENSEMODE, &io, 0, 0, tc, sizeof(*tc), 0, 0, 0, 0); /* Check status */ return FAILURE(status) && FAILURE(io.i_cond); } /*** * vmsstty - Set terminal control block * * vmsstty takes a previous vmsgtty with modifications, and stores * this as the current terminal control block. * * Returns: Status ***/ int vmsstty(tc) struct termchar * tc; /* Terminal characteristics */ { int status; struct iosb io; /* Set terminal characteristics */ status = SYS$QIOW(1, channel, IO$_SETMODE, &io, 0, 0, tc, sizeof(*tc), 0, 0, 0, 0); /* Check status */ return FAILURE(status) && FAILURE(io.i_cond); } /*** * vmsclose - Close the connection to the terminal * * vmsclose resets the terminal to the original state and cuts the * connection. No further operations should be done after closing. * * Nothing returned. ***/ vmsclose() { /* Flush pending output */ vmsflush(); /* Do this stupid thing for synchronization */ SYS$QIOW(1, channel, IO$_WRITELBLK | IO$M_NOFORMAT, 0, 0, 0, " \b", 2, 0, 0, 0, 0); /* Reset terminal to original modes */ vmsstty(&oldmode); /* Release channel */ SYS$DASSGN(channel); } /*** * vmsopen - Get terminal type and open terminal * * Nothing returned ***/ vmsopen() { $DESCRIPTOR(name, "TT"); int status; /* Open channel to terminal */ status = SYS$ASSIGN(&name, &channel, 0, 0); if (FAILURE(status)) { printf(TEXT195); /* "Cannot open channel to terminal.\n" */ exit(1); } /* Get terminal type */ if (vmsgtty(&oldmode)) { printf(TEXT196); /* "Cannot obtain terminal settings.\n" */ goto error; } /* Get SMG */ if (vmscap()) goto error; /* Set sizes */ term.t_nrow = ((unsigned int) oldmode.t_mandl >> 24) - 1; term.t_ncol = oldmode.t_width; /* Set new terminal modes */ newmode = oldmode; newmode.t_extend |= TT2$M_PASTHRU; if (vmsstty(&newmode)) { printf(TEXT197); /* "Cannot modify terminal settings.\n" */ goto error; } /* Finished! */ return; /* Make sure terminal deassigned */ error: /* Release channel */ SYS$DASSGN(channel); exit(1); } /*** * vmsflush - Flush output buffer * * vmsflush causes all queued output characters to be written to the * terminal's screen. We will use SYS$QIO because we don't need to * wait and because it dramaticly increases performance. * * Nothing returned. ***/ vmsflush() { int len; /* Compute size of request */ len = outbuft - outbuf; /* Skip if zero */ if (len) { SYS$QIO(0, channel, IO$_WRITELBLK | IO$M_NOFORMAT, 0, 0, 0, outbuf, len, 0, 0, 0, 0); /* Reset buffer positions */ outbuft = outbuf; } } /*** * vmsputc - Send a character to the screen * * vmsputc queues character into a buffer for screen output. When the * buffer is full the flush routine is called. This is help speed * things up by avoiding millions of system calls. * * Nothing returned. ***/ vmsputc(ch) char ch; /* Character to add */ { /* Check for overflow */ if (outbuft == &outbuf[sizeof(outbuf)]) vmsflush(); /* Add character to buffer */ *outbuft++ = ch; } /*** * vmsputs - Send a string to vmsputc * * vmsputs is a short-cut routine to handle sending a string of characters * to the character output routine. A check is made for a NULL string, * while is considered valid. A NULL string will produce no output. * * Nothing returned. ***/ vmsputs(string) char * string; /* String to write */ { if (string) while (*string) vmsputc(*string++); } /*** * vmsgchar - Get character directly from VMS * * vmsgchar is the lowest level of retrieving character from VMS. * The argument timed specifies where to wait for a character for * a short period (1 > wait >= 2 seconds) or indefinately. The short * period version is used when obtaining a escape sequence. * * Returns: character or 0 if no character is available. ***/ char vmsgchar(timed) int timed; /* TRUE if being timed */ { char ch; int status, op; struct iosb io; /* Make operation */ op = (timed ? IO$M_TIMED : 0) | IO$_READLBLK | IO$M_NOECHO; /* Get next character */ status = SYS$QIOW(1, channel, op, &io, 0, 0, &ch, 1, 2, 0, 0, 0); /* Fatal error */ if (FAILURE(status) || FAILURE(io.i_cond)) { /* Check for time-out */ if (io.i_cond == SS$_TIMEOUT) return 0; /* Real I/O error occured */ printf(TEXT198, status, io.i_cond); /* "I/O error (%d,%d)\n" */ SYS$DASSGN(channel); exit(1); } /* Return next character */ return ch; } /*** * vmsqin - Queue character for input * * vmsqin queues the character into the input buffer for later * reading. This routine will mostly be used by mouse support * and other escape sequence processing. * * Nothing returned. ***/ vmsqin(ch) char ch; /* Character to add */ { /* Check for overflow */ if (inbuft == &inbuf[sizeof(inbuf)]) { /* Annoy user */ vmsbeep(); return; } /* Add character */ *inbuft++ = ch; } /*** * vmsgcook - Get characters from input device * * vmsgcook "cooks" input from the input device and places them into * the input queue. * * Nothing returned. ***/ vmsgcook() { char ch; struct keyent * cur; /* Get first character untimed */ ch = vmsgchar(0); vmsqin(ch); /* Skip if the key isn't a special leading escape sequence */ if (keyseq[(unsigned char) ch] == 0) return; /* Start translating */ cur = keymap; while (cur) { if (cur->ch == ch) { /* Is this the end */ if (cur->nxtlvl == NULL) { /* Replace all character with new sequence */ inbuft = inbuf; vmsqin(0); vmsqin(cur->code); return; } else { /* Advance to next level */ cur = cur->nxtlvl; /* Get next character, timed */ ch = vmsgchar(1); if (ch == '\0') return; /* Queue character */ vmsqin(ch); } } else /* Try next character on same level */ cur = cur->samlvl; } } /*** * vmsgetc - Get a character * * vmsgetc obtains input from the character input queue. If the queue * is empty, a call to vmsgcook() is called to fill the input queue. * * Returns: character ***/ int vmsgetc() { char ch; /* Loop until character found */ while (1) { /* Get input from buffer, if available */ if (inbufh != inbuft) { ch = *inbufh++; if (inbufh == inbuft) inbufh = inbuft = inbuf; break; } else /* Fill input buffer */ vmsgcook(); } /* Return next character */ return (int) ch; } #if FLABEL /*** * fnclabel - Label function keys * * Currently, VMS does not have function key labeling. * * Returns: status. ***/ int fnclabel(flag, n) int flag; /* TRUE if default */ int num; /* Numerical argument */ { /* On machines with no function keys...don't bother */ return TRUE; } #endif /* FLABEL */ /*** * spal - Set palette type * * spal sets the palette colors for the 8 colors available. Currently, * there is nothing here, but some DEC terminals, (VT240 and VT340) have * a color palette which is available under the graphics modes. * Further, a foreign terminal could also change color registers. * * Nothing returned ***/ spal() { /* Nothing */ } #endif /* VMSVT */ #if TYPEAH /*** * typahead - Check for pending input * * typahead check the input buffer for pending input. If input exists * TRUE is returned. This routine is used mostly by the display * update routine to avoid redrawing the entire display when it * doesn't need to do so. * * Returns: boolean. ***/ int typahead() { int status; struct iosb io; struct tahd tbuf; /* Check for buffered characters */ if (inbufh != inbuft) return TRUE; /* Call to system for character count */ status = SYS$QIOW(1, channel, IO$_SENSEMODE | IO$M_TYPEAHDCNT, &io, 0, 0, &tbuf, sizeof(tbuf), 0, 0, 0, 0); if (FAILURE(status) || FAILURE(io.i_cond)) return FALSE; return tbuf.t_count; } #endif /* TYPEAH */ /*** * vmsdcl - Execute or invoke a DCL * * vmsdcl without an argument will invoke a new DCL as a new process * and attach to it. When the DCL returns, emacs will regain control. * With an argument, the DCL starts and begins executing the command * line. * * Returns: status. ***/ int vmsdcl(command) char * command; /* Command to execute */ { int result, status; struct dsc$descriptor desc, * dp; /* Set up descriptor */ if (command) { desc.dsc$a_pointer = command; desc.dsc$w_length = strlen(command); desc.dsc$b_dtype = DSC$K_DTYPE_T; desc.dsc$b_class = DSC$K_CLASS_S; dp = &desc; } else dp = NULL; /* Turn off raw input */ vmsstty(&oldmode); /* Call DCL */ status = LIB$SPAWN(dp, 0, 0, 0, 0, 0, &result, 0, 0, 0); /* Return to raw input */ vmsstty(&newmode); /* Return status */ return SUCCESS(status) && SUCCESS(result); } /*** * spawncli - Spawn a new DCL * * spawncli reliquishes control of the terminal and passes it on to * a newly created DCL process. When the DCL process finishes, the * screen is redrawen and emacs regains control. * * Returns: status ***/ int spawncli(flag, num) int flag; /* TRUE if default */ int num; /* Numerical argument */ { /* Restrict usage */ if (restflag) return resterr(); /* Move to last line and announce */ vmsmove(term.t_nrow, 0); vmsputs(TEXT199); /* "[Starting DCL]\r\n" */ vmsflush(); /* Redraw screen on return */ sgarbf = TRUE; /* Start command */ return vmsdcl(NULL); } /*** * spawn - Spawn a command * * spawncli reliquishes control of the terminal and passes it on to * a newly created DCL process. When the DCL process finishes, the * screen is redrawen and emacs regains control. * * Returns: status ***/ int spawn(flag, num) int flag; /* TRUE if default */ int num; /* Numerical argument */ { char line[NLINE]; int status; /* Restrict usage */ if (restflag) return resterr(); /* Ask for command */ status = mlreply("!", line, sizeof(line)); if (status != TRUE) return status; /* Move to last line and announce */ vmsmove(term.t_nrow, 0); vmsputs(TEXT200); /* "[Calling DCL]\r\n" */ vmsflush(); /* Run command */ status = vmsdcl(line); /* Wait for conformation */ vmsputs(TEXT6); /* "\r\n\n[END]" */ vmsflush(); vmsgchar(); /* Redraw screen on return */ sgarbf = TRUE; return status; } /*** * execprg - Execute a program without using command interpretter * * execprg is the same as spawn because there is no reasonable way * of avoiding the command interpretter. This routine is mostly for * smaller systems. * * Returns: status ***/ int execprg(flag, num) int flag; /* TRUE if default */ int num; /* Numerical argument */ { return spawn(flag, num); } /*** * pipecmd - Pipe a one line command into a window * * pipecmd take a single command and places output into a buffer. * This is accomplished on non-UNIX machines by sending the result * of the command interpretter into a temporary file, then reading * the file into the buffer. * * This command is not implemented current, but could be implemented * and will be once I get some manuals. * * Returns: status ***/ int pipecmd(flag, num) int flag; /* TRUE if default */ int num; /* Numerical argument */ { mlwrite(TEXT201); /* "[Not available yet under VMS]" */ return FALSE; } /*** * filter - Filter buffer through an external command * * filter take a buffer and pipes into a program. This is accomplished * under non-UNIX systems by writing the buffer to a temporary file * and running the command with the temporary file as input and another * temporary file as output. Once the command completes, the buffer * is replaced by the contents of the second temporary file and * all temporary files are removed. * * This command is currently not implemented, but can be implemented * and will be once I get the manuals. * * Returns: status. ***/ int filter(flag, num) int flag; /* TRUE if default */ int num; /* Numerical argument */ { mlwrite(TEXT201); /* "[Not available yet under VMS]" */ return FALSE; } /* return a system dependant string with the current time */ char *PASCAL NEAR timeset() { register char *sp; /* temp string pointer */ char buf[16]; /* time data buffer */ extern char *ctime(); time(buf); sp = ctime(buf); sp[strlen(sp)-1] = 0; return(sp); } #else vmshello() { } #endif
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.