[comp.sys.amiga] program question, stdin, stdout.

kushmer@bnlux0.bnl.gov (christopher kushmerick) (07/28/90)

The following program use to be my standard first program on a new computer.
But it does not seem to work on my 2000, when compiled under lattice 5.0x..

#include stdio.h

main()
{
	while ((c=getchar())!=EOF) putchar(c);
}


When I replace putchar with printf("%d\n",c) the program works as I woud
expect, it prints out the ascii value of the character I hit.

Any ideas why the above prog should not work?

-- 
Chris Kushmerick

kushmer@bnlux0.bnl.gov
kushmerick@pofvax.sunysb.edu

robin@sabre.austin.ibm.com (Robin D. Wilson/1000000) (07/30/90)

In article <2033@bnlux0.bnl.gov> kushmer@bnlux0.bnl.gov (christopher kushmerick) writes:
>#include stdio.h
>
>main()
>{
>	while ((c=getchar())!=EOF) putchar(c);
>}
>When I replace putchar with printf("%d\n",c) the program works as I woud
>expect, it prints out the ascii value of the character I hit.
>
>Any ideas why the above prog should not work?

Just a wild guess.. but maybe putchar() is trying to put a character, when "c" 
is an int?  (I really don't remember.)


+-----------------------------------------------------------------------------+
|The views expressed herein, are the sole responsibility of the typist at hand|
+-----------------------------------------------------------------------------+
|UUCP:     cs.utexas.edu!ibmchs!auschs!sabre.austin.ibm.com!robin             |
|USNail:   701 Canyon Bend Dr.                                                |
|          Pflugerville, TX  78660                                            |
|          Home: (512)251-6889      Work: (512)823-4526                       |
+-----------------------------------------------------------------------------+

jmeissen@oregon.oacis.org ( Staff OACIS) (07/31/90)

In article <2033@bnlux0.bnl.gov> kushmer@bnlux0.bnl.gov (christopher kushmerick) writes:
>	while ((c=getchar())!=EOF) putchar(c);
>When I replace putchar with printf("%d\n",c) the program works as I woud
>expect, it prints out the ascii value of the character I hit.
>Any ideas why the above prog should not work?


Yes, the problem is that by default stdout is buffered. When you call putchar() (a macro,
I think) it merely puts characters into a buffer until the buffer fills up, then it gets
flushed. printf() gets around this problem by calling fflush() each time it gets called.

You can either set stdout to unbuffered by calling setnbf(), or call fflush() after each
putchar() call.
-- 
John Meissen .............................. Oregon Advanced Computing Institute
jmeissen@oacis.org        (Internet) | "That's the remarkable thing about life;
..!sequent!oacis!jmeissen (UUCP)     |  things are never so bad that they can't
jmeissen                  (BIX)      |  get worse." - Calvin & Hobbes

S.J.Raybould@fulcrum.bt.co.uk (Simon Raybould) (08/01/90)

In article <573@oregon.oacis.org> jmeissen@oregon.oacis.org ( Staff OACIS) writes:
>>When I replace putchar with printf("%d\n",c) the program works as I woud
>
>Yes, the problem is that by default stdout is buffered. When you call putchar() (a macro,
>I think) it merely puts characters into a buffer until the buffer fills up, then it gets

This is the normal operation of stdio.


>flushed. printf() gets around this problem by calling fflush() each time it gets called.

RUBBISH!!! printf() doesn't call fflush() each time it is called. The above
example works because there is a newline at the end which WILL cause printf()
to flush the stdio buffer. printf() uses stdio and will flush the same as all
other stdio functions i.e. when the buffer is full or a forwarding condition
is met such as \n.

SJR


+-=-=-=-=-=-=-=-=-=-=-=-=-=-=+=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-+
|   British Telecom Fulcrum  | name : Simon John Raybould   {^.^}   |
|   Fordrough Lane           | path : sie@fulcrum.bt.co.uk   \~/    |
|   Birmingham               +-----------+--------------------------|
|   B9 5LD                   |   //      | AMIGA B2000HD 3MB 8088BB |
|   ENGLAND                  | \X/AMIGA  | Lattice C V5.05          |
+-=-=-=-=-=-=-=-=-=-=-=-=-=-=+=-=-=-=-=-=+=-=-=-=-=-=-=-=-=-=-=-=-=-+

jmeissen@oregon.oacis.org ( Staff OACIS) (08/02/90)

-- 
John Meissen .............................. Oregon Advanced Computing Institute
jmeissen@oacis.org        (Internet) | "That's the remarkable thing about life;
..!sequent!oacis!jmeissen (UUCP)     |  things are never so bad that they can't
jmeissen                  (BIX)      |  get worse." - Calvin & Hobbes

jmeissen@oregon.oacis.org ( Staff OACIS) (08/02/90)

In article <7N6$5X*@masalla.fulcrum.bt.co.uk> S.J.Raybould@fulcrum.bt.co.uk (Simon Raybould) writes:
 >In article <573@oregon.oacis.org> jmeissen@oregon.oacis.org ( Staff OACIS) writes:
 >>flushed. printf() gets around this problem by calling fflush() each time it gets called.
 >
 >RUBBISH!!! printf() doesn't call fflush() each time it is called. The above
 >example works because there is a newline at the end which WILL cause printf()
 >to flush the stdio buffer. printf() uses stdio and will flush the same as all
 >other stdio functions i.e. when the buffer is full or a forwarding condition
 >is met such as \n.

If you please, I'm the one who put the fflush call into the printf function in the
Lattice C library. I think I know what I'm talking about.


 >
 >SJR
 >
-- 
John Meissen .............................. Oregon Advanced Computing Institute
jmeissen@oacis.org        (Internet) | "That's the remarkable thing about life;
..!sequent!oacis!jmeissen (UUCP)     |  things are never so bad that they can't
jmeissen                  (BIX)      |  get worse." - Calvin & Hobbes

root@bcstarc.stgt.sub.org (Frank Pecher) (08/02/90)

In article <2033@bnlux0.bnl.gov> kushmer@bnlux0.bnl.gov (christopher kushmerick) writes:
>#include stdio.h
>
>main()
>{
>      while ((c=getchar())!=EOF) putchar(c);
>}
>When I replace putchar with printf("%d\n",c) the program works as I woud
>expect, it prints out the ascii value of the character I hit.
>
>Any ideas why the above prog should not work?

I noticed the same problem; if you use putchar(), the output doesn't occur
until you send an EOF. With printf() everything works alright. Maybe this
problem is dependent on the compiler; I use Lattice 5.05. What compiler
did you use?

        --  Frank

--
Frank Pecher                           uucp: root@bcstarc.stgt.sub.org
==>              (This line intentionally left blank)              <==

walker@unx.sas.com (Doug Walker) (08/03/90)

In article <2033@bnlux0.bnl.gov> kushmer@bnlux0.bnl.gov (christopher kushmerick) writes:
>main()
>{
>	while ((c=getchar())!=EOF) putchar(c);
>}
>
>
>When I replace putchar with printf("%d\n",c) the program works as I woud
>expect, it prints out the ascii value of the character I hit.

Getchar and putchar are both buffered.  To make them unbuffered, use the
rawio functions that Chuck McManis did a few years back, on a low-numbered
fish disk, or ConsoleIO by Jim Cooper on disk 69.  here's Chuck's stuff:


Many times I have wanted to set 'stdin' in my programs to what is often
referred to as 'CBREAK' mode. Basically, that means that every time you
call getchar() you get a character. Up until now there was no easy way
to do that. The enclosed shar file contains three files, testraw.c
raw.c and sendpacket.c. The interesting one is raw.c which contains the
functions raw() and cooked(). These take a file pointer (FILE *) and
convert it to raw mode or cooked mode respectively. The testraw.c file
shows how it is done. Note that this will probably only work for Lattice
users since it uses the Lattice ios1.h file to find the DOS FileHandle
associated with a 'Level 2' file. Anyway, it was short so it is included
here complete.

--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
These opinions are my own and no one elses, but you knew that didn't you.
------------------------------CUT HERE--------------------------------
/* 
 *	raw.c
 *
 *    This is a routine for setting a given stream to raw or cooked mode.
 * This is useful when you are using Lattice C to produce programs that
 * want to read single characters with the "getch()" or "fgetc" call.
 *
 * Written : 18-Jun-87 By Chuck McManis. 
 * 	     If you use it I would appreciate credit for it somewhere.
 */
#include <exec/types.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>
#include <stdio.h>
#include <ios1.h>
#include <error.h>

/* New Packet in 1.2 */
#define ACTION_SCREEN_MODE	994L

extern	int	errno;		/* The error variable */

/*
 * Function raw() - Convert the specified file pointer to 'raw' mode. This
 * only works on TTY's and essentially keeps DOS from translating keys for
 * you, also (BIG WIN) it means getch() will return immediately rather than
 * wait for a return. You lose editing features though.
 */
long
raw(fp)

FILE *fp;

{
  struct MsgPort 	*mp; /* The File Handle message port */
  struct FileHandle 	*afh;
  struct UFB 		*ufb;
  long			Arg[1],res;

  ufb = (struct UFB *) chkufb(fileno(fp));  /* Step one, get the file handle */
  afh = (struct FileHandle *)(ufb->ufbfh); 

  if (!IsInteractive(afh)) {	/* Step two, check to see if it's a console */
    errno = ENOTTY;
    return(-1);
  }
                              /* Step three, get it's message port. */
  mp  = ((struct FileHandle *)(BADDR(afh)))->fh_Type;
  Arg[0] = -1L;
  res = SendPacket(mp,ACTION_SCREEN_MODE,Arg,1); /* Put it in RAW: mode */
  if (res == 0) {
    errno = ENXIO;
    return(-1);
  }
  return(0);
}

/*
 * Function - cooked() this function returns the designate file pointer to
 * it's normal, wait for a <CR> mode. This is exactly like raw() except that
 * it sends a 0 to the console to make it back into a CON: from a RAW:
 */

long
cooked(fp)

FILE *fp;

{
  struct MsgPort 	*mp; /* The File Handle message port */
  struct FileHandle 	*afh;
  struct UFB 		*ufb;
  long			Arg[1],res;

  ufb = (struct UFB *) chkufb(fileno(fp));
  afh = (struct FileHandle *)(ufb->ufbfh);
  if ( ! IsInteractive(afh)) {
    errno = ENOTTY;
    return(-1);
  }
  mp  = ((struct FileHandle *)(BADDR(afh)))->fh_Type;
  Arg[0] = 0;
  res = SendPacket(mp,ACTION_SCREEN_MODE,Arg,1);
  if (res == 0) {
    errno = ENXIO;
    return(-1);
  }
  return(0);
}
------------------------------CUT HERE--------------------------------
/*
 *	testraw.c
 *
 *   This program shows how to use the functions raw() and cooked() to
 * control the way characters are read from a Level 2 file pointer.
 * These are only useful if the file pointer points at an instance of
 * the console.device, which means one of 'stdin', 'stdout', or 'stderr'
 * or a console opened with fp = fopen("CON:x/y/wid/len/Title","w+");
 * like this example does. 
 *
 * Written : 16-Jun-87 By Chuck McManis, do with it what you will.
 *
 */

#include <stdio.h>
#ifndef u_char
#define	u_char	unsigned char
#endif

void main()

{
  FILE	*win;
  char	c;
  long	i;

  printf("This program shows how to use raw mode file pointers.\n");
  printf("First we open the window...\n");
  win = fopen("CON:10/10/400/100/Test Console","w+");
/* If opening a file, use setnbf() to set it to unbuffered mode, this is
 * very importatant. Not required for stdin since Lattice defaults it to
 * unbuffered. 
 */
  setnbf(win);
  fprintf(win,"Using the default mode, type some characters ... \n");  
  fprintf(win,"Type a 'Q' to go to next phase ... \n");  
  i = 0;
  while ((c = fgetc(win)) != 'Q') {
    i = (i + 1) % 25;
    if (i == 0) printf("\n");
    printf(" %02x",(u_char) c);
  }
  printf("\n************\n");
  fprintf(win,"Now switching to 'raw' mode ...\n");
  fprintf(win,"Type a 'Q' to go to next phase ... \n");  
  if (raw(win) != 0) perror("raw");
  i = 0;
  while ((c = fgetc(win)) != 'Q') {
    i = (i + 1) % 25;
    if (i == 0) printf("\n");
    printf(" %02x",(u_char) c);
  }
  printf("\n************\n");
  fprintf(win,"Now back to 'cooked' mode ... \n");
  fprintf(win,"Type a 'Q' to quit ... \n");  
  if (cooked(win) != 0) perror("cooked");
  i = 0;
  while ((c = fgetc(win)) != 'Q') {
    i = (i + 1) % 25;
    if (i == 0) printf("\n");
    printf(" %02x",(u_char) c);
  }
  fclose (win);
}
------------------------------CUT HERE--------------------------------
/*
 *	Sendpacket.c 
 *
 *  An invaluable addition to your Amiga.lib file. This code sends a packet
 * the given message port. This makes working around DOS lots easier.
 * 
 * Note, I didn't write this, those wonderful folks at CBM did. I do suggest
 * however that you may wish to add it to Amiga.Lib, to do so, compile it
 * and say 'oml lib:amiga.lib -r sendpacket.o' 
 */

#include <exec/types.h>
#include <exec/ports.h>
#include <exec/memory.h>
#include <libraries/dos.h>
#include <libraries/dosextens.h>

/*
 * Function - SendPacket written by Phil Lindsay, Carolyn Scheppner, and
 * Andy Finkel. This function will send a packet of the given type to the
 * Message Port supplied.
 */

long
SendPacket(pid,action,args,nargs)

struct MsgPort *pid;  /* process indentifier ... (handlers message port ) */
long action,          /* packet type ... (what you want handler to do )   */
     args[],          /* a pointer to a argument list */
     nargs;           /* number of arguments in list  */
{
  struct MsgPort        *replyport;
  struct StandardPacket *packet;
 
  long  count, *pargs, res1;

  replyport = (struct MsgPort *) CreatePort(NULL,0);
  if(!replyport) return(0);

  /* Allocate space for a packet, make it public and clear it */
  packet = (struct StandardPacket *) 
    AllocMem((long)sizeof(struct StandardPacket),MEMF_PUBLIC|MEMF_CLEAR);
  if(!packet) {
    DeletePort(replyport);
    return(0);
  }

  packet->sp_Msg.mn_Node.ln_Name = (char *)&(packet->sp_Pkt);
  packet->sp_Pkt.dp_Link         = &(packet->sp_Msg);
  packet->sp_Pkt.dp_Port         = replyport;
  packet->sp_Pkt.dp_Type         = action;

  /* copy the args into the packet */
  pargs = &(packet->sp_Pkt.dp_Arg1);       /* address of first argument */
  for(count=0;count < nargs;count++) 
    pargs[count]=args[count];
 
  PutMsg(pid,packet); /* send packet */

  WaitPort(replyport);
  GetMsg(replyport); 

  res1 = packet->sp_Pkt.dp_Res1;

  FreeMem(packet,(long)sizeof(struct StandardPacket));
  DeletePort(replyport); 

  return(res1);
}
------------------------------CUT HERE--------------------------------
OBJ =		raw.o sendpacket.o testraw.o
CC =		lc
CFLAGS = -cwusf -d -E

testraw :	$(OBJ)
		blink lib:c.o $(OBJ) to testraw lib lib:lc.lib lib:amiga.lib sc sd verbose

testraw.o: testraw.c
sendpacket.o: sendpacket.c
raw.o: raw.c

.c.o :
		$(CC) $(CFLAGS) $*
------------------------------CUT HERE--------------------------------
Article 5545 of comp.sys.amiga:
Path: mcdsun!noao!hao!husc6!mit-eddie!genrad!decvax!decwrl!pyramid!oliveb!sun!pepper!cmcmanis
From: cmcmanis%pepper@Sun.COM (Chuck McManis)
Newsgroups: comp.sys.amiga
Subject: Set your console to raw mode
Keywords: cbreak() raw() cooked()
Message-ID: <21174@sun.uucp>
Date: 16 Jun 87 09:09:27 GMT
Sender: news@sun.uucp
Lines: 256

Many times I have wanted to set 'stdin' in my programs to what is often
referred to as 'CBREAK' mode. Basically, that means that every time you
call getchar() you get a character. Up until now there was no easy way
to do that. The enclosed shar file contains three files, testraw.c
raw.c and sendpacket.c. The interesting one is raw.c which contains the
functions raw() and cooked(). These take a file pointer (FILE *) and
convert it to raw mode or cooked mode respectively. The testraw.c file
shows how it is done. Note that this will probably only work for Lattice
users since it uses the Lattice ios1.h file to find the DOS FileHandle
associated with a 'Level 2' file. Anyway, it was short so it is included
here complete.

--Chuck McManis
uucp: {anywhere}!sun!cmcmanis   BIX: cmcmanis  ARPAnet: cmcmanis@sun.com
These opinions are my own and no one elses, but you knew that didn't you.

phorgan@cup.portal.com (Patrick John Horgan) (08/03/90)

Note that Aztec users can use ioctl to set CBREAK mode, or use the
set_raw(), set_con() pair to switch back and forth between buffered
and unbuffered I/O.

Patrick Horgan                        phorgan@cup.portal.com

gt5784a@prism.gatech.EDU (Walter G. Reynolds (JJ)) (08/06/90)

In article <69@bcstarc.stgt.sub.org> root!bcstarc@nadia.UUCP (Frank Pecher) writes:
>In article <2033@bnlux0.bnl.gov> kushmer@bnlux0.bnl.gov (christopher kushmerick) writes:

[program deleted]

>>When I replace putchar with printf("%d\n",c) the program works as I woud
>>expect, it prints out the ascii value of the character I hit.
>>
>>Any ideas why the above prog should not work?

[more stuff deleted]

Try using fflush().  I use DICE, and I noticed that if you use several
printf statements, and none of them have a newline, that they won't actually
get printed until way too late.... I solved this problem by using
                
                        fflush(stdout)
What's happening, is that the data is getting sent to a buffer or something,
and the buffer is never being physically (in C terms) written out to stdout.

I hope this helps.. it fixed my problem under DICE.....

Walter (JJ) Reynolds.

-- 
This .signature is being released as ShareWare.  This means that if you
like it, you are morally obligated to send your .signature to me in
return.  Send your .sigs to: gt5784a@prism.gatech.edu.  Any donations
will be used for future .sig releases.   

fgd3@jc3b21.UUCP (Fabbian G. Dufoe) (08/07/90)

Try adding a call to fflush() after your putchar().  Putchar() outputs to
the stdout buffer, but that doesn't guarantee you the buffer will be
written to the output device.  Fflush() flushes the buffers so you know all
output is complete.

--Fabbian Dufoe
  350 Ling-A-Mor Terrace South
  St. Petersburg, Florida  33705
  813-823-2350

UUCP: fgd3@jc3b21.UUCP
      ...uunet!pdn!jc3b21!fgd3

rick@tmiuv0.uucp (08/09/90)

In article <979@jc3b21.UUCP>, fgd3@jc3b21.UUCP (Fabbian G. Dufoe) writes:
> Try adding a call to fflush() after your putchar().  Putchar() outputs to
> the stdout buffer, but that doesn't guarantee you the buffer will be
> written to the output device.  Fflush() flushes the buffers so you know all
> output is complete.

Very true.  One could also use the setvbuf() function to cause stdout to be
non-buffered.  In most - but not all - cases, this will obviate the need to
call fflush(stdout).  setvbuf() is defined by ANSI, I believe, the prototype
is:

    int setvbuf(FILE *stream, char *buf, int mode, int size);

----------------------------------------------------------------------------
[- O] Rick Stevens
  ?   EMail: uunet!zardoz!tmiuv0!rick -or- uunet!zardoz!xyclone!sysop
  V   CIS: 75006,1355 (75006.1355@compuserve.com from Internet)

"Reality is a crutch for people who can't handle science fiction."
----------------------------------------------------------------------------