ugwayne@sunybcs.UUCP (01/09/87)
Subject: Unbuffered I/O using MicroSoft C Version 3.0 ----------------------------------------------------- A friend of mine recently asked me "If I knew of a program that would let your printer act like a typewriter?". Since a program of this sort seemed really easy to write (just get characters and send them to the printer), I decided I would just write one myself. Well, I am sorry to say, things have not been as easy as I thought they would be. The problem is that I can't get the printer to just print one character at a time. It only prints out a line at a time. I am using MicroSoft C 3.0 and I have tried various methods but each time the printer only prints out when I enter a Carriage Return. At first, I was using getc() and putc() and then it dawned on me that these functions use buffered I/O. So I looked in the MicroSoft manuals and found the function setbuf. I tried this on the stream stdprn and then ran the program again. It still didn't work. Next, I used the functions read() and write() which the manual states as low-level I/O that do not buffer or format data. But again, the program will not work the way I want it to. The Carriage Return is still needed to start the print. Then, I thought that it might be that the printer was getting the characters one at a time (so the pogram was working) and it may need a Carriage Return before it does any printing (it had its own buffering). With this in mind then I decided to just try my program with the standard input and output devices. So when I hit a key, I would not only see my keystroke but also another one which my program was then sending. This too, did not work, a Carriage Return was still needed. So what I would like to know then, Is how would I get a program like this to work? How do you get unbuffered I/O using MicroSoft C 3.0? What am I doing wrong? If anyone has any suggestions, I would sure appreciate a response. This is really driving me crazy. Thanks in advance, Wayne Wayne Nelligan SUNY at Buffalo Computer Science ------------------------------------------------------------------------- .{bbncca,decvax,dual,rocksvax,watmath,sbcs}!sunybcs!ugwayne CSNET: ugwayne@Buffalo.CSNET ARPANET: ugwayne%Buffalo@csnet-relay.ARPA BITNET: ugwayne@sunybcs.BITNET
larry@kitty.UUCP (Larry Lippman) (01/09/87)
In article <1867@sunybcs.UUCP>, ugwayne@sunybcs (Wayne Nelligan) writes: > A friend of mine recently asked me "If I knew of a program that would let > your printer act like a typewriter?". Since a program of this sort seemed > really easy to write (just get characters and send them to the printer), I > decided I would just write one myself. Well, I am sorry to say, things have > not been as easy as I thought they would be. The problem is that I can't get > the printer to just print one character at a time. It only prints out a line > at a time. > I am using MicroSoft C 3.0 and I have tried various methods but each time > the printer only prints out when I enter a Carriage Return. > [further discussion of C I/O functions] The problem you relate has nothing to do with C programming or the nature of your operating system - it strictly pertains to the functional characteristics of your printer. Many electromechanical printers using wire-matrices, bands, chains printwheels, etc. can only print the line buffer all at once (this is an inherent printer design characteristic). Most "better-quality" printers of the above genre will permit "overprinting" of a line; i.e., printing a line buffer without advancing the paper. Comparatively few printers (that are also NOT KSR terminals) will truly print one character at a time. To cite a few examples from looking around my lab: 1. AT&T/Teletype 40P202 (132 col 300 lpm chain printer): <CR> prints the line buffer without advancing the paper <NL> prints the line buffer with advancing the paper NO single-character printing 2. Okidata Microline 82A (120 cps wire-matrix printer): <CR> prints the line buffer with advancing the paper <NL> advances the paper one line but prints nothing NO single-character printing 3. Centronics Horizon H136A (120 cps wire-matrix printer): <CR> prints the line buffer without advancing the paper, provided that an option switch is set to disable paper advance on <CR> <NL> prints the line buffer with advancing the paper NO single-character printing 3. Centronics 703 (120 cps wire-matrix printer): <CR> prints the line buffer without advancing the paper <NL> advances the paper one line but prints nothing NO single-character printing Note the different characteristics of the above printers. By far, the Okidata is the "cheapest" of the above printers, and there just ain't no way to get it to print other than a whole line along with advancing the paper. Now you should see where your problem lies. There may be a way around the problem under some circumstances - keep overprinting, with each successive overprint using space characters to force the desired character into proper position. However, this does seem to be rather extreme. There is an important moral to what may seem like a trivial discussion: Depending upon your printer and its configuration, simple C statements directing output to a printer (i.e., though a stream defined as a printer using fputc, fputs, fprintf, etc.) may NOT do what you think they should! <> Larry Lippman @ Recognition Research Corp., Clarence, New York <> UUCP: {allegra|bbncca|decvax|nike|rocksanne|watmath}!sunybcs!kitty!larry <> VOICE: 716/688-1231 {hplabs|ihnp4|mtune|seismo|utzoo}!/ <> FAX: 716/741-9635 {G1,G2,G3 modes} "Have you hugged your cat today?"
tom@uw-warp.UUCP (Tom May) (01/12/87)
In article <1867@sunybcs.UUCP>, ugwayne@sunybcs (Wayne Nelligan) writes: > I am using MicroSoft C 3.0 and I have tried various methods but each time > the printer only prints out when I enter a Carriage Return. At first, I was > using getc() and putc() and then it dawned on me that these functions > use buffered I/O. So I looked in the MicroSoft manuals and found the > function setbuf. I tried this on the stream stdprn and then ran the program > again. It still didn't work. What's going on is that your terminal input is line-buffered so you can use backspace, function keys, etc. A setbuf on stdin won't turn off this buffering, since it is done by MS-DOS before the C library gets hold of your characters. You have to invoke MS-DOS directly, as demonstrated below. > Next, I used the functions read() and write() which the manual states as > low-level I/O that do not buffer or format data. That may be true, but the very-low-level I/O routines, i.e., MS-DOS, may still buffer stuff. And in fact they do, at least as far as terminal input is concerned. > Then, I thought that it might be that the printer was getting > the characters one at a time (so the pogram was working) and it may need a > Carriage Return before it does any printing (it had its own buffering). Your printer could indeed do this type of buffering, especially if it is bi-directional (wouldn't make a good typewriter in the first place anyway if so). If it does, you're out of luck. > With this in mind then I decided to just try my program with the standard > input and output devices. So when I hit a key, I would not only see my > keystroke but also another one which my program was then sending. This too, > did not work, a Carriage Return was still needed. Interesting. What should happen is you will see MS-DOS echo characters as you type them, then when you hit return (after any line-editing) they will all be handed to your program which would echo them again. Weird. So, here is the promised routine which invokes MS-DOS to get a character from the keyboard (not stdin) without echoing it. It also does some things which are obvious from looking at the code. #include <dos.h> int grokchar() { union REGS regs; regs.h.ah = 7; /* get char no echo */ intdos (®s, ®s); return (regs.h.al == 26 ? EOF : regs.h.al == '\r' ? '\n' : regs.h.al); } The MS-DOS interrupts are documented in the MS-DOS Technical Reference Manual, so if you want one that echos you can look it up there. I think there is also one to pass a character to the printer. Stuff like this is why I think MS-DOS stands for Massively Suckful DOS. Personally, I'd use either a real typewriter or an editor for this job. -- Tom May. uw-beaver!uw-nsr!uw-warp!tom (So, do I pass the Turing test?)
backman@interlan.UUCP (Larry Backman) (01/12/87)
In article <1867@sunybcs.UUCP> ugwayne@sunybcs.UUCP (Wayne Nelligan) writes: > > >Subject: Unbuffered I/O using MicroSoft C Version 3.0 >----------------------------------------------------- > > > A friend of mine recently asked me "If I knew of a program that would let >your printer act like a typewriter?". > I am using MicroSoft C 3.0 and I have tried various methods but each time >the printer only prints out when I enter a Carriage Return. At first, I was >using getc() and putc() and then it dawned on me that these functions >use buffered I/O. > So what I would like to know then, Is how would I get a program like >this to work? How do you get unbuffered I/O using MicroSoft C 3.0? I've never tried this particular problem, but having gone through similar experiences with DOS and various C compilers, I would suggest the brute forc approach. Replace the BIOS keyboard and printr handlers with your own interrupt handlers, then play read a char... write a char... out of the interrupt service routines. Its not as clean as using a C call, but you won't have unknowns in your way. Larry Backman Micom - Interlan, Inc. ulowell !interlan!backman
reintom@rocky2.UUCP (Tom Reingold) (01/12/87)
In article <1867@sunybcs.UUCP>, ugwayne@sunybcs (Wayne Nelligan) writes: > > A friend of mine recently asked me "If I knew of a program that would let > your printer act like a typewriter?". Since a program of this sort seemed > really easy to write (just get characters and send them to the printer), I > decided I would just write one myself. Well, I am sorry to say, things have > not been as easy as I thought they would be. The problem is that I can't get > the printer to just print one character at a time. It only prints out a line > at a time. > [...] > So what I would like to know then, Is how would I get a program like > this to work? How do you get unbuffered I/O using MicroSoft C 3.0? > What am I doing wrong? If anyone has any suggestions, I > would sure appreciate a response. This is really driving me crazy. > > Thanks in advance, > Wayne You are probably automatically generating unbuffered output but the printer buffers its input until a line is full. A line is full either when it gets a CR or when its length is reached. You can fool it with the method outlined in the enclosed program. Good luck. Tom ======================================================================== #include <stdio.h> #define CR '\r' #define LF '\n' #define TAB '\t' #define SPACE ' ' /* * This is an example program. It reads the standard input * and prints it to the standard printer, one character * at a time. Tabs and other subtle things will not work * because it is an example to show you that you can do * what you want to. * * The printer prints when the line length is reached or * when it gets a RETURN character. This program sends one * after each character. * */ main() { char line[256]; int i, j; while ((gets(line)) != NULL) { for (i=0; i < strlen(line); i++) { fputc(line[i], stdprn); fputc(CR, stdprn); fputc(SPACE, stdprn); for (j=0; j < i; j++) fputc(SPACE, stdprn); } fputc(LF, stdprn); } } -- Tom Reingold; The Rockefeller University; 1230 York Av; NY 10021 PHONE: (212) 570-7709 [office]; (212) 304-2504 [home] ARPANET: reintom@rockefeller.arpa BITNET: REINTOM@ROCKVAX UUCP: {seismo|ihnp4|yale|harvard|philabs|phri}!cmcl2!rna!rocky2!reintom
reintom@rocky2.UUCP (Tom Reingold) (01/12/87)
[] Ok, this program more closely addresses the problem you describe. As you can see, this small problem has been fun for me. ================================================================= #include <stdio.h> #define CR '\r' #define LF '\n' #define SPACE ' ' #define ESC '\033' /* * This is an example program. It directly reads the keyboard * and prints to the standard printer, one character * at a time. Tabs and other subtle things will not work * because it is an example to show you that you can do * what you want to. * * The printer prints when the line length is reached or * when it gets a RETURN character. This program sends one * after each character. * * This program exits after the user presses ESCAPE. * */ main() { int i, linelen, c; linelen = 0; while ((c=getche()) != ESC) { fputc(c, stdprn); if (c != CR) { linelen++; fputc(CR, stdprn); for (i = 0; i < linelen; i++) fputc(SPACE, stdprn); fflush(stdprn); } else { linelen = 0; putchar(LF); fputc(LF, stdprn); fflush(stdprn); } } fputc(LF, stdprn); } -- Tom Reingold; The Rockefeller University; 1230 York Av; NY 10021 PHONE: (212) 570-7709 [office]; (212) 304-2504 [home] ARPANET: reintom@rockefeller.arpa BITNET: REINTOM@ROCKVAX UUCP: {seismo|ihnp4|yale|harvard|philabs|phri}!cmcl2!rna!rocky2!reintom
campbell@maynard.BSW.COM (Larry Campbell) (01/14/87)
Summary: Can't read a character at a time using Microsoft C; program sees no input until carriage return typed. A respondent erroneously blamed the printer on which the C program was echoing its output; the respondent failed to note that the original poster had thought of that and had tried sending output to the console, with identical results. This problem has nothing to do with Microsoft C. It is a feature of DOS. Standard input (the console) is normally opened by DOS in ASCII mode, in which a program reading from stdin blocks until a carriage return is typed. To be woken up on every character, you need to put stdin into binary mode. You do this with the IOCTL DOS call (INT 21, AH=44). Do subfunction AL=0 first to get the mode bits (returned in DX), then set the "binary" bit (bit 5), then do subfunction 1 to set the mode bits (from DX). For both calls, the file handle goes in BX. Note that binary mode will also disable ^S and ^C processing. Don't forget to put the console back in ASCII mode! -- Larry Campbell The Boston Software Works, Inc. Internet: campbell@maynard.uucp 120 Fulton Street, Boston MA 02109 uucp: {alliant,wjh12}!maynard!campbell +1 617 367 6846 ARPA: campbell%maynard.uucp@harvisr.harvard.edu MCI: LCAMPBELL
sbanner1@uvicctr.UUCP (S. John Banner) (01/15/87)
In article <645@uw-warp.UUCP> tom@uw-warp.UUCP (Tom May) writes: >In article <1867@sunybcs.UUCP>, ugwayne@sunybcs (Wayne Nelligan) writes: >So, here is the promised routine which invokes MS-DOS to get a >character from the keyboard (not stdin) without echoing it. It also >does some things which are obvious from looking at the code. > >#include <dos.h> >int >grokchar() { > union REGS regs; > > regs.h.ah = 7; /* get char no echo */ > intdos (®s, ®s); > return (regs.h.al == 26 ? EOF : regs.h.al == '\r' ? '\n' : regs.h.al); >} you can actually do the same thing without resorting to DOS in mscv4.0, and I understand it works in earlyer versions as well (I got the trick from a freind of mine using v2.something). grokchar() { while (!kbhit()) ; return getc(); } I am not totally sure that I have the right funtion names here, but I know they are pretty close (you might try fgetc if getc doesn't work), and I may have the wrong name for kbhit, but the names should be pretty obvious. S. John Banner ...!uw-beaver!uvicctr!sbanner1 ccsjb@uvvm sbanner1@uvunix.UVIC.CDN
cramer@kontron.UUCP (Clayton Cramer) (01/16/87)
> Summary: Can't read a character at a time using Microsoft C; program > sees no input until carriage return typed. > > A respondent erroneously blamed the printer on which the C program > was echoing its output; the respondent failed to note that the > original poster had thought of that and had tried sending output > to the console, with identical results. > > This problem has nothing to do with Microsoft C. It is a feature of DOS. > Standard input (the console) is normally opened by DOS in ASCII mode, in > which a program reading from stdin blocks until a carriage return is typed. > > To be woken up on every character, you need to put stdin into binary mode. > You do this with the IOCTL DOS call (INT 21, AH=44). Do subfunction AL=0 > first to get the mode bits (returned in DX), then set the "binary" bit > (bit 5), then do subfunction 1 to set the mode bits (from DX). For both > calls, the file handle goes in BX. > > Note that binary mode will also disable ^S and ^C processing. Don't forget > to put the console back in ASCII mode! > -- > Larry Campbell The Boston Software Works, Inc. Even easier: #include <fcntl.h> setmode (fileno (stdin), O_BINARY); /* You are now in binary mode on stdin. */ setmode (fileno (stdin), O_TEXT); /* You are back in text mode on stdin. */ Clayton E. Cramer
tom@uw-warp.UUCP (01/22/87)
In article <217@uvicctr.UUCP>, sbanner1@uvicctr.UUCP (S. John Banner) writes: > In article <645@uw-warp.UUCP> tom@uw-warp.UUCP (Tom May) writes: > >So, here is the promised routine which invokes MS-DOS to get a > >character from the keyboard (not stdin) without echoing it. [deleted routine] > you can actually do the same thing without resorting to DOS in mscv4.0, > and I understand it works in earlyer versions as well (I got the trick > from a freind of mine using v2.something). > > grokchar() > { > while (!kbhit()) > ; > return getc(); > } > > I am not totally sure that I have the right funtion names here, but I > know they are pretty close (you might try fgetc if getc doesn't work), > and I may have the wrong name for kbhit, but the names should be pretty > obvious. > > S. John Banner > > ...!uw-beaver!uvicctr!sbanner1 > ccsjb@uvvm > sbanner1@uvunix.UVIC.CDN Actually, the following routine does the job: int grokchar () { return getch(); } This routine can also be optimized away in an obvious manner. But if your C library doesn't have a getch(), you have to do it with intdos or whatever low-level hook type stuff is available. The kbhit() is unnecessary since getch() waits for a character. Btw, kbhit() is the only weird MS-C library console i/o type extension that can't be done with an intdos, since the corresponding DOS function returns its status in the z flag, which is not in `union REGS'.-- Tom May. uw-beaver!uw-nsr!uw-warp!tom (So, do I pass the Turing test?)
tom@uw-warp.UUCP (01/25/87)
In article <645@uw-warp.UUCP>, I, tom@uw-warp.UUCP (Tom May), wrote: > So, here is the promised routine which invokes MS-DOS to get a > character from the keyboard (not stdin) without echoing it. It also > does some things which are obvious from looking at the code. > > #include <dos.h> > int > grokchar() { > union REGS regs; > > regs.h.ah = 7; /* get char no echo */ > intdos (®s, ®s); > return (regs.h.al == 26 ? EOF : regs.h.al == '\r' ? '\n' : regs.h.al); > } It turns out that the statement about reading the keyboard, not stdin, was incorrect. Although the function is called Direct Console Input or something like that (my DOS machine + manuals are 15 miles away from my USENET machine), further inspection of the DOS Technical Reference manual reveals that all those so-called console routines actually read stdin. Even the Keyboard Input function reads stdin! (At least the doc says it does, I haven't tried it.) I discovered this when I redirected the input to a program I had written that used the above function and found that it worked, much to my surprise. Also, the MSC library routines getch() and getche() use DOS functions which read characters from stdin, not con as the manual seems to imply. I just wanted to clear this up before someone else made me look bad. :-) -- Tom May. uw-beaver!uw-nsr!uw-warp!tom
perry@omepd.UUCP (01/28/87)
In article <650@uw-warp.UUCP> tom@uw-warp.UUCP (Tom May) writes: > [Describing a way to call the MS-DOS INT 21 direct console input function] > ... >It turns out that the statement about reading the keyboard, not stdin, was >incorrect. Although the function is called Direct Console Input or something >like that (my DOS machine + manuals are 15 miles away from my USENET machine), >further inspection of the DOS Technical Reference manual reveals that all those >so-called console routines actually read stdin. Even the Keyboard Input >function reads stdin! (At least the doc says it does, I haven't tried it.) > >Also, the MSC library routines getch() and getche() use DOS functions which >read characters from stdin, not con as the manual seems to imply. Right! This one got me too, first time I tried it. My MS-DOS programmer's reference says *standard input* all the way, but with a name like *console input*... There is a quite simple way to make sure that stdin is really the keyboard. The (MSC) call sequence close(0); dup(2); effectively duplicates the stderr channel onto stdin. As you can't redirect stderr in MSDOS (at least from COMMAND.COM), this is sure to be the keyboard. That sequence loses whatever was redirected into stdin, of course. If you need it, you can use code like this: FILE *stin; stin=fopen("NUL","r"); /* grab a free file slot */ close(fileno(stin)); dup(0); /* duplicate stdin into stin */ close(0); dup(2); /* duplicate stderr into stdin */ From then on, *stdin* is the keyboard and *stin* is what was piped into your program. It seems that the theoretically different I/O modes (stderr writing, stdin reading) don't make any difference to MS-DOS. Btw, this code should work in any language that accesses MS-DOS file handles directly; it uses a MS-DOS feature, not a MSC speciality. Hope this help you... ------------------------------------------------------------------------ << Perry The Cynic >> ...!tektronix!ogcvax!omepd!inteloa!perry ...!verdix!omepd!inteloa!perry (Peter Kiehtreiber) -or try- perry@inteloa.intel.com
bet@ecsvax.UUCP (01/29/87)
While setbuf will still be needed to get unbuffered I/O, there is a wondrously simple way to ensure that I/O doesn't get redirected without mucking about with DOS interrupts! Like so: FILE *fopen(), *console; console = fopen("\\dev\\con", "r"); The '\' characters are doubled because '\' is the quoting character in C strings; you can simplify the above to the more obvious: FILE *fopen(), *console; console = fopen("con", "r"); (or "con:", or whatever floats your boat) if you are guaranteed that your program will never be run on a system using the undocumented DOS AVAILDEV function to hide devices. -Bennett P.S. AVAILDEV: Issue DOS function call INT 21H with AH=37H to access SWITCHAR and AVAILDEV: AL=0 read SWITCHAR value into DL AL=1 set SWITCHAR from DL AL=2 read AVAILDEV into DL AL=3 set AVAILDEV from DL The SWITCHAR is the character used for "switches" in DOS command arguments (defaults to '/', as in "DIR /P"). '-' is popular to make a system look more like UNIX; if the SWITCHAR is anything other than '/', then '/' may be used instead of '\' for pathnames (even more like UNIX!). AVAILDEV=0 means than devices must be referenced in an imaginary subdirectory "\dev" (shades of UNIX's /dev/*); a filename "prn.dat" can be created on disk and manipulated like any other. If AVAILDEV != 0 then device names are recognized anywhere (this is the default): "prn.dat" is synonymous with "prn:". NOTE: These functions are undocumented, whicn means they are unsupported, which means they are liable to go away whenever Microsoft is feeling frisky. Use at your own risk! However, PLEASE program around them to make life nicer for the daring souls who take the risk. -Bennett -- Bennett Todd -- Duke Computation Center, Durham, NC 27706-7756; (919) 684-3695 UUCP: ...{decvax,seismo,philabs,ihnp4,akgua}!mcnc!ecsvax!duccpc!bet BITNET: DBTODD@TUCC.BITNET -or- DBTODD@TUCCVM.BITNET -or- bet@ECSVAX.BITNET terrorist, cryptography, DES, drugs, cipher, secret, decode, NSA, CIA, NRO.
kneller@ucsfcgl.UUCP (02/01/87)
In article <2609@ecsvax.UUCP> bet@ecsvax.UUCP (Bennett E. Todd III) writes: > >While setbuf will still be needed to get unbuffered I/O, there is a >wondrously simple way to ensure that I/O doesn't get redirected without >mucking about with DOS interrupts! Like so: > > FILE *fopen(), *console; > > console = fopen("\\dev\\con", "r"); One caveat is that the open will sometimes fail running under DOS 2.x. DOS 3.x doesn't have this problem. Don Kneller UUCP: ...ucbvax!ucsfcgl!kneller ARPA: kneller@cgl.ucsf.edu BITNET: kneller@ucsfcgl.BITNET