Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!decvax!decwrl!ucbvax!YALE.ARPA!LEICHTER-JERRY From: LEICHTER-JERRY@YALE.ARPA.UUCP Newsgroups: mod.computers.vax Subject: Re: VAX C problem (?) - reading single characters with VAX C Message-ID: <8607200525.AA21652@ucbvax.Berkeley.EDU> Date: Sun, 20-Jul-86 01:26:25 EDT Article-I.D.: ucbvax.8607200525.AA21652 Posted: Sun Jul 20 01:26:25 1986 Date-Received: Sun, 20-Jul-86 11:01:47 EDT Sender: daemon@ucbvax.BERKELEY.EDU Reply-To: Organization: The ARPA Internet Lines: 257 Approved: info-vax@sri-kl.arpa A recent message from Samuel Baxter (brspyr1!sam) provided a simple program to do single-character terminal I/O on VMS. Enclosed below is a program that does the same thing, though often much more efficiently, since it buffers up typed-ahead stuff. In addition, it can be do "non-blocking" terminal reads. The program has a long history and several people have hacked at it - I'm just the last. It's been used successfully for quite some time. It differs form Mr. Baxter's code in not attempting to trap CTRL/C. That, and related changes, can be made easily enough. Mr. Baxter also asks why VAX C provides crmode() only as a dummy function, and does not provide getpass(). A guess at the answers: crmode() has some very specific effects on Unix that would be very difficult to duplicate exactly on VMS - different purposes of crmode() would probably want to use slightly different combinations of VMS terminal settings. For example, should crmode() disable xon/xoff (CTRL/Q - CTRL/S) handling? To be exactly like Unix, probab- ly, but for most purposes, in a VMS environment, the probably not. The Unix and VMS terminal drivers are so different that any attempt to provide anything beyond the usual buffered I/O is going to run into problems. As to getpass(), it's pretty rarely used outside of the kind of system pro- grams that are unlikely to be moved to VMS - I'll bet at least 90% of Unix programmers have never heard of it - and it's pretty easy to write anyway. So, it must have come far down on the list of things to get written. -- Jerry ------------------------------Cut Here------------------------------------------ /*#define TESTING */ /* * k b i n . c * * Read tt: one byte at a time without echo, with or without waiting if there * is no typeahead. * * Synopsis * * int * _kbin(wait) * int wait; * * int * kbin() * * int * kbinr_() * * Description * * Returns the next character. Returns EOF on error, or if there is no * typeahead and "no wait" was requested. * * _kbin(wait) waits if wait is TRUE, returns EOF if there is no * typeahead and wait is FALSE. kbin() is the same as _kbin(TRUE); * kbinr() is the same as _kbin(FALSE). * * Note -- this routine does not prevent CTRL/C or CTRL/Y aborts * from occurring. * * Revision History * 0.0 19-Jun-79 SB Original version due to Stoney Ballard. * 0.1 19-Oct-79 MM "Munged". * 0.2 31-Aug-81 MM Name changed to kbin(). * 1.0 ??-???-?? MM Made part of VAXLIB. * 1.1 22-Jul-83 JSL Old kbin() ==> _kbin() and gets the "wait" argument; * kbin(), kbinr() in terms of _kbin(). */ #include #include #include #include #define FALSE 0 #define TRUE 1 #define EOS 0 #define BUFFLEN 10 /* Size of typeahead buffer */ /* * Local static database: */ static $DESCRIPTOR(inpdev, "TT"); /* Terminal to use for input */ static long termset[2] = { 0, 0 }; /* No terminator */ /* * Local variables */ static long ichan; /* Gets channel number for TT: */ static char opened = FALSE; /* TRUE when opened */ static char ibuff[BUFFLEN]; /* Input buffer -- one byte */ static char *buffptr = ibuff; /* For typeahead processing */ static char *buffend = ibuff; /* For typeahead processing */ int _kbin(wait) int wait; /* * Get one byte without echoing, with or without waiting. */ { register int errorcode; struct IOSTAB { short int status; short int offset_to_terminator; short int terminator; short int terminator_size; } iostab; if (buffptr < buffend) return (*buffptr++ & 0377); /* Empty our typeahead buffer */ if (!opened) { if ((errorcode = sys$assign(&inpdev, &ichan, 0, 0)) != SS$_NORMAL) { fprintf(stderr, "KBIN assign failed. code = %X\n", errorcode); exit(errorcode); } else opened = TRUE; } /* * See if there's something in the system typeahead buffer * Read up to BUFLEN bytes with "zero" timeout. This will return * whatever's in the timeout buffer. The iostab.offset_to_terminator * and iostab.terminator_size will yield the number of bytes read. */ errorcode = sys$qiow(1, /* Event flag */ ichan, /* Input channel */ IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR | IO$M_TIMED, /* Timed read with zero wait */ &iostab, /* I/O status block */ NULL, /* AST block (none) */ 0, /* AST parameter */ &ibuff, /* P1 - input buffer */ BUFFLEN, /* P2 - buffer length */ 0, /* P3 - ignored (timeout) */ &termset, /* P4 - terminator set */ NULL, /* P5 - ignored (prompt buffer) */ 0); /* P6 - ignored (prompt size) */ #ifdef TESTING printf("timed read code = %X, ", errorcode); printf("status = %d, offset = %d, terminator = %d, size = %d\n", iostab.status, iostab.offset_to_terminator, iostab.terminator, iostab.terminator_size); #endif buffend = &ibuff[iostab.offset_to_terminator + iostab.terminator_size]; if (buffend > ibuff) { buffptr = &ibuff[1]; /* Setup typeahead pointer and */ return (ibuff[0] & 0377); /* Return the first character */ } /* * Nothing in typeahead buffer, nothing read. If the user doesn't * want us to wait, just return EOF; else read one character. */ if (!wait) return (EOF); errorcode = sys$qiow(1, /* Event flag */ ichan, /* Input channel */ IO$_READLBLK | IO$M_NOECHO | IO$M_NOFILTR, /* Read, no echo, no translate */ &iostab, /* I/O status block */ NULL, /* AST block (none) */ 0, /* AST parameter */ &ibuff, /* P1 - input buffer */ 1, /* P2 - buffer length */ 0, /* P3 - ignored (timeout) */ &termset, /* P4 - terminator set */ NULL, /* P5 - ignored (prompt buffer) */ 0); /* P6 - ignored (prompt size) */ #ifdef TESTING printf("read one byte, code = %X, ", errorcode); printf("status = %d, offset = %d, terminator = %d, size = %d\n", iostab.status, iostab.offset_to_terminator, iostab.terminator, iostab.terminator_size); #endif if (errorcode == SS$_NORMAL) { return (ibuff[0] & 0377); } else { return (EOF); } } int kbin() /* * Get one byte without echoing, with waiting. */ { return (_kbin(TRUE)); } int kbinr() /* * Get one byte without echoing, without waiting. */ { return (_kbin(FALSE)); } #ifdef TESTING main() { register int datum; printf("kbin() testing - CTRL/Z to exit\n"); while ((datum = kbin()) != EOF) { printf("%03o '", datum); dumpc(datum); printf("'\n"); if (datum == ('Z' - 0100)) break; } printf("EOF\n"); printf("kbinr() testing - CTRL/Z to exit\n"); while (1) { datum = kbinr(); if (datum == EOF) { printf("EOF - sleeping..."); sleep(2); printf("\n"); continue; } printf("%03o '", datum); dumpc(datum); printf("'\n"); if (datum == ('Z' - 0100)) break; } printf("EOF\n"); } dumpc(datum) int datum; /* * Dump a character readably */ { datum &= 0377; if ((datum & 0200) != 0) { putchar('~'); datum &= 0177; } if (datum < ' ') { putchar('^'); putchar(datum + '@'); } else if (datum > 0176) { printf(""); } else putchar(datum); } #endif -------