linux-c-programming.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* stdio
@ 2003-06-18  9:58 John T. Williams
  2003-06-18 12:02 ` stdio Jan-Benedict Glaw
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: John T. Williams @ 2003-06-18  9:58 UTC (permalink / raw)
  To: linux-c-programming

I am trying to figure out how to cause a character to be printed to a
specific place on the terminal

what I'm actually trying to accomplish is to make a progress bar

example:

Progress [*****                           ]  25%

and I want it to fill up the box with stars as my program progresses, but I
can't figure out how to just get c to write a single '*'  to anywhere other
then the end of the streak
I tried lseek and got no good results.

I'd really like any advice anyone has on this.


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: stdio
  2003-06-18  9:58 stdio John T. Williams
@ 2003-06-18 12:02 ` Jan-Benedict Glaw
  2003-06-18 12:17 ` stdio Luciano Moreira - igLnx
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 10+ messages in thread
From: Jan-Benedict Glaw @ 2003-06-18 12:02 UTC (permalink / raw)
  To: linux-c-programming

[-- Attachment #1: Type: text/plain, Size: 1402 bytes --]

On Wed, 2003-06-18 05:58:42 -0400, John T. Williams <jtwilliams@vt.edu>
wrote in message <011801c33580$48425aa0$e764a8c0@fesnel.noip.org>:
> I am trying to figure out how to cause a character to be printed to a
> specific place on the terminal
> 
> what I'm actually trying to accomplish is to make a progress bar
> 
> example:
> 
> Progress [*****                           ]  25%
> 
> and I want it to fill up the box with stars as my program progresses, but I
> can't figure out how to just get c to write a single '*'  to anywhere other
> then the end of the streak
> I tried lseek and got no good results.

Well, what you want to do sounds quite simple, but it's really quite
complicated. The basic problem is that there are thousands of different
terminal types out there which need different control sequences to
position the cursor (if possible at all). You would need to know all of
them to be portable.

Because that would be a real PITA, this functionality has been placed
into some libraries. Look for libncurses (of libtermcap) to do this
task...

MfG, JBG

-- 
   Jan-Benedict Glaw       jbglaw@lug-owl.de    . +49-172-7608481
   "Eine Freie Meinung in  einem Freien Kopf    | Gegen Zensur | Gegen Krieg
    fuer einen Freien Staat voll Freier Bürger" | im Internet! |   im Irak!
      ret = do_actions((curr | FREE_SPEECH) & ~(IRAQ_WAR_2 | DRM | TCPA));

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: stdio
  2003-06-18  9:58 stdio John T. Williams
  2003-06-18 12:02 ` stdio Jan-Benedict Glaw
@ 2003-06-18 12:17 ` Luciano Moreira - igLnx
  2003-06-18 13:04 ` stdio Stephen Satchell
  2003-06-18 18:30 ` stdio Chris Nanakos
  3 siblings, 0 replies; 10+ messages in thread
From: Luciano Moreira - igLnx @ 2003-06-18 12:17 UTC (permalink / raw)
  To: John T. Williams; +Cc: linux-c-programming

Look for documentation of Curses. Its a framework that encapsulate the 
character sequences to keep your program portable over different terminals.

Luciano

John T. Williams wrote:

>I am trying to figure out how to cause a character to be printed to a
>specific place on the terminal
>
>what I'm actually trying to accomplish is to make a progress bar
>
>example:
>
>Progress [*****                           ]  25%
>
>and I want it to fill up the box with stars as my program progresses, but I
>can't figure out how to just get c to write a single '*'  to anywhere other
>then the end of the streak
>I tried lseek and got no good results.
>
>I'd really like any advice anyone has on this.
>
>-
>To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in
>the body of a message to majordomo@vger.kernel.org
>More majordomo info at  http://vger.kernel.org/majordomo-info.html
>
>
>  
>


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: stdio
  2003-06-18  9:58 stdio John T. Williams
  2003-06-18 12:02 ` stdio Jan-Benedict Glaw
  2003-06-18 12:17 ` stdio Luciano Moreira - igLnx
@ 2003-06-18 13:04 ` Stephen Satchell
  2003-06-18 17:45   ` stdio Glynn Clements
  2003-06-18 18:30 ` stdio Chris Nanakos
  3 siblings, 1 reply; 10+ messages in thread
From: Stephen Satchell @ 2003-06-18 13:04 UTC (permalink / raw)
  To: John T. Williams, linux-c-programming

At 05:58 AM 6/18/2003 -0400, John T. Williams wrote:
>I am trying to figure out how to cause a character to be printed to a
>specific place on the terminal
>
>what I'm actually trying to accomplish is to make a progress bar
>
>example:
>
>Progress [*****                           ]  25%
>
>and I want it to fill up the box with stars as my program progresses, but I
>can't figure out how to just get c to write a single '*'  to anywhere other
>then the end of the streak
>I tried lseek and got no good results.
>
>I'd really like any advice anyone has on this.

The really "classic" way to do what you want to do is to rewrite the entire 
line each time you add a progress indicator.    This is the basic idea:

    int i;
    char progress[52];

    memset(progress, 0, 52);
    for (i = 0; i <50; i++)
     {
     fprintf(stderr, "%1.26s [%-50s]\r", "some.text", progress);
     progress[i] = '*';
     GoDoOneFiftyithOfSomething();
     }
    fprintf(stderr, "%1.26s [%-50s]\n", "some.text", progress);

This avoids the need to use termcap or terminfo, or the curses package.  It 
works with all non-paper terminals, but it's SLOW if you are on a real 
teletype and HORRIBLE on some kludge like a keypunch-cardreader/printer 
console.  (Not likely today, but...)

Hope this helps.

Satch


^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: stdio
  2003-06-18 13:04 ` stdio Stephen Satchell
@ 2003-06-18 17:45   ` Glynn Clements
  0 siblings, 0 replies; 10+ messages in thread
From: Glynn Clements @ 2003-06-18 17:45 UTC (permalink / raw)
  To: John T. Williams; +Cc: Stephen Satchell, linux-c-programming


Stephen Satchell wrote:

> > I am trying to figure out how to cause a character to be printed to a
> > specific place on the terminal
> > 
> > what I'm actually trying to accomplish is to make a progress bar
> > 
> > example:
> > 
> > Progress [*****                           ]  25%
> > 
> > and I want it to fill up the box with stars as my program progresses, but I
> > can't figure out how to just get c to write a single '*'  to anywhere other
> > then the end of the streak
> > I tried lseek and got no good results.
> > 
> > I'd really like any advice anyone has on this.
> 
> The really "classic" way to do what you want to do is to rewrite the entire 
> line each time you add a progress indicator.    This is the basic idea:
> 
>     int i;
>     char progress[52];
> 
>     memset(progress, 0, 52);
>     for (i = 0; i <50; i++)
>      {
>      fprintf(stderr, "%1.26s [%-50s]\r", "some.text", progress);
>      progress[i] = '*';
>      GoDoOneFiftyithOfSomething();
>      }
>     fprintf(stderr, "%1.26s [%-50s]\n", "some.text", progress);
> 
> This avoids the need to use termcap or terminfo, or the curses package.  It 
> works with all non-paper terminals,

Not quite. It doesn't work with emulators such as Emacs' shell-mode,
which just dumps everything into the buffer.

For correctness, you should use termcap/terminfo to check whether the
terminal (as specified by $TERM) has the "cr" capability before
writing '\r' to the terminal.

Also, you should check whether stderr is actually a terminal (with
isatty()) before doing this sort of thing; you don't want to be doing
it if stderr is redirected to a file.

However, using curses for this would be overkill. You only need to use
curses if you need vertical positioning.

-- 
Glynn Clements <glynn.clements@virgin.net>

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: stdio
  2003-06-18  9:58 stdio John T. Williams
                   ` (2 preceding siblings ...)
  2003-06-18 13:04 ` stdio Stephen Satchell
@ 2003-06-18 18:30 ` Chris Nanakos
  2003-06-19  7:33   ` I'm really starting to dislike stdio John T. Williams
  3 siblings, 1 reply; 10+ messages in thread
From: Chris Nanakos @ 2003-06-18 18:30 UTC (permalink / raw)
  To: John T. Williams, linux-c-programming

Try this.....and make your own changes....if helps just send an e-mail!!!

#This is a progress bar with iterations
#A lot of implementations can exist.Try this one and tell me if its done or
else i will send another one.

#include <stdio.h>

main()
{
    int progress,j;
    progress=1;
    for(j=0;j<=100;j++)
{
    if(progress(!=101)
{int i;
printf("\33[1;34m");
    printf("\r|");
for(;i<50;i++)
    fprintf(stdout," ");
fprintf(stdout,"%6.2f %%",(float)2.5*progress);
fflush(stdout);
    progress++;
}
usleep(40000);
}
printf("\33[0m");
printf("\n");
return;
}




^ permalink raw reply	[flat|nested] 10+ messages in thread

* I'm really starting to dislike stdio
  2003-06-18 18:30 ` stdio Chris Nanakos
@ 2003-06-19  7:33   ` John T. Williams
  2003-06-19 11:26     ` Jan-Benedict Glaw
  2003-06-19 12:56     ` Andrés Roldán
  0 siblings, 2 replies; 10+ messages in thread
From: John T. Williams @ 2003-06-19  7:33 UTC (permalink / raw)
  To: linux-c-programming

I really appricated the help with the progress bar.

I have another problem

I am trying to read in a password from the stdin, but I don't want it to
display to the screen as the person types it in.
I either like to mock su, and take input w/o any output, or output a *  for
each typed character, and I cannot figure out how to get this to work

I've tried
_____________________

        read(1, &tmpch, 1);

        while(tmpch != '\n') {
                memset(prog, '*', stars);
                printf("\rPassword: %-20s ", prog );
                stars++;

                buff[loop] = tmpch;
                loop++;
                read(1, &tmpch, 1);
        }
        read(1, &tmpch, 1);

        while(tmpch != '\n') {
                memset(prog, '*', stars);
                printf("\rPassword: %-20s ", prog );
                stars++;

                buff[loop] = tmpch;
                loop++;
                read(1, &tmpch, 1);
        }
--------------------------

I've tried

____________________


tmpch = getchar();
while(tmpch != '\n') {
    memset(prog, '*', stars)
    printf("\rPassword: %-20s ", prog );
    stars++;

    buff[loop] = tmpch;
    loop++;
    tmpch = getchar();
}

and I tried getc from the curses library.
The problem with all of these is that they only actually do the read part
after I've hit the <enter> key.  I want it to process each character as it
is typed.  Anyone who has any ideas or can tell me a better way to read
characters w/o displaying it to the screen and I'd be greatful.



^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: I'm really starting to dislike stdio
  2003-06-19  7:33   ` I'm really starting to dislike stdio John T. Williams
@ 2003-06-19 11:26     ` Jan-Benedict Glaw
  2003-06-19 17:39       ` Glynn Clements
  2003-06-19 12:56     ` Andrés Roldán
  1 sibling, 1 reply; 10+ messages in thread
From: Jan-Benedict Glaw @ 2003-06-19 11:26 UTC (permalink / raw)
  To: linux-c-programming

[-- Attachment #1: Type: text/plain, Size: 2083 bytes --]

On Thu, 2003-06-19 03:33:16 -0400, John T. Williams <jtwilliams@vt.edu>
wrote in message <004001c33635$21f3d3a0$e764a8c0@fesnel.noip.org>:
> I really appricated the help with the progress bar.
> 
> I have another problem
> 
> I am trying to read in a password from the stdin, but I don't want it to
> display to the screen as the person types it in.
> I either like to mock su, and take input w/o any output, or output a *  for
> each typed character, and I cannot figure out how to get this to work

> and I tried getc from the curses library.
> The problem with all of these is that they only actually do the read part
> after I've hit the <enter> key.  I want it to process each character as it
> is typed.  Anyone who has any ideas or can tell me a better way to read
> characters w/o displaying it to the screen and I'd be greatful.

Terminals are serial equipment with special characteristics:) First, a
call to read() will only return after the user pressed his Enter key
_until_ you fiddle with serial settings:

struct termios termio;
tcgetattr(STDIN_FILENO, &termio);
termio.c_cc[V_MIN] = 1; /* Return after one byte */
tcsetattr(STDIN_FILENO, &termio);
tcflush(STDIN_FILENO, TCIOFLUSH);

(Of course, you need a second struct termios to memcpy() all the old
values to be able to restore the previous state which you're expected to
do.)

The second part is to not let those characters appear at all. This is
done with:

struct termios termio;
tcgetattr(STDIN_FILENO, &termio);
termio_new.c_lflag &= ~ECHO; /* Clear ECHO flag */
tcsetattr(STDIN_FILENO, &termio);
tcflush(STDIN_FILENO, TCIOFLUSH);

(Again, you need to backup old termios settings.)

Serial programming (which this is, after all) isn't 100% simple:(

MfG, JBG

-- 
   Jan-Benedict Glaw       jbglaw@lug-owl.de    . +49-172-7608481
   "Eine Freie Meinung in  einem Freien Kopf    | Gegen Zensur | Gegen Krieg
    fuer einen Freien Staat voll Freier Bürger" | im Internet! |   im Irak!
      ret = do_actions((curr | FREE_SPEECH) & ~(IRAQ_WAR_2 | DRM | TCPA));

[-- Attachment #2: Type: application/pgp-signature, Size: 189 bytes --]

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: I'm really starting to dislike stdio
  2003-06-19  7:33   ` I'm really starting to dislike stdio John T. Williams
  2003-06-19 11:26     ` Jan-Benedict Glaw
@ 2003-06-19 12:56     ` Andrés Roldán
  1 sibling, 0 replies; 10+ messages in thread
From: Andrés Roldán @ 2003-06-19 12:56 UTC (permalink / raw)
  To: John T. Williams; +Cc: linux-c-programming

man 3 getpass

Cheers

"John T. Williams" <jtwilliams@vt.edu> writes:

> I really appricated the help with the progress bar.
>
> I have another problem
>
> I am trying to read in a password from the stdin, but I don't want it to
> display to the screen as the person types it in.
> I either like to mock su, and take input w/o any output, or output a *  for
> each typed character, and I cannot figure out how to get this to work
>
> I've tried
> _____________________
>
>         read(1, &tmpch, 1);
>
>         while(tmpch != '\n') {
>                 memset(prog, '*', stars);
>                 printf("\rPassword: %-20s ", prog );
>                 stars++;
>
>                 buff[loop] = tmpch;
>                 loop++;
>                 read(1, &tmpch, 1);
>         }
>         read(1, &tmpch, 1);
>
>         while(tmpch != '\n') {
>                 memset(prog, '*', stars);
>                 printf("\rPassword: %-20s ", prog );
>                 stars++;
>
>                 buff[loop] = tmpch;
>                 loop++;
>                 read(1, &tmpch, 1);
>         }
> --------------------------
>
> I've tried
>
> ____________________
>
>
> tmpch = getchar();
> while(tmpch != '\n') {
>     memset(prog, '*', stars)
>     printf("\rPassword: %-20s ", prog );
>     stars++;
>
>     buff[loop] = tmpch;
>     loop++;
>     tmpch = getchar();
> }
>
> and I tried getc from the curses library.
> The problem with all of these is that they only actually do the read part
> after I've hit the <enter> key.  I want it to process each character as it
> is typed.  Anyone who has any ideas or can tell me a better way to read
> characters w/o displaying it to the screen and I'd be greatful.
>
>
> -
> To unsubscribe from this list: send the line "unsubscribe linux-c-programming" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html

-- 
Andres Roldan <aroldan@fluidsignal.com>
http://people.fluidsignal.com/~aroldan
CSO, Fluidsignal Group

^ permalink raw reply	[flat|nested] 10+ messages in thread

* Re: I'm really starting to dislike stdio
  2003-06-19 11:26     ` Jan-Benedict Glaw
@ 2003-06-19 17:39       ` Glynn Clements
  0 siblings, 0 replies; 10+ messages in thread
From: Glynn Clements @ 2003-06-19 17:39 UTC (permalink / raw)
  To: John T. Williams; +Cc: linux-c-programming, Jan-Benedict Glaw


Jan-Benedict Glaw wrote:

> > I really appricated the help with the progress bar.
> > 
> > I have another problem
> > 
> > I am trying to read in a password from the stdin, but I don't want it to
> > display to the screen as the person types it in.
> > I either like to mock su, and take input w/o any output, or output a *  for
> > each typed character, and I cannot figure out how to get this to work
> 
> > and I tried getc from the curses library.
> > The problem with all of these is that they only actually do the read part
> > after I've hit the <enter> key.  I want it to process each character as it
> > is typed.  Anyone who has any ideas or can tell me a better way to read
> > characters w/o displaying it to the screen and I'd be greatful.
> 
> Terminals are serial equipment with special characteristics:) First, a
> call to read() will only return after the user pressed his Enter key
> _until_ you fiddle with serial settings:
> 
> struct termios termio;
> tcgetattr(STDIN_FILENO, &termio);
> termio.c_cc[V_MIN] = 1; /* Return after one byte */
> tcsetattr(STDIN_FILENO, &termio);
> tcflush(STDIN_FILENO, TCIOFLUSH);

Note: tcsetattr() takes 3 arguments.

Alternatively:

	tcgetattr(STDIN_FILENO, &termio);
	termio.c_lflag &= ~ICANON;
	tcsetattr(STDIN_FILENO, TCSANOW, &termio);

This will disable the terminal driver's line-buffering altogether. It
also disables the processing of special characters (backspace, Ctrl-C,
Ctrl-Z etc).

For this particular situation (reading passwords), setting c_cc[V_MIN]
is probably preferable, but for fully "raw" I/O you need to clear the
ICANON flag.

If you want to use ANSI I/O, you also need:

	setbuf(stdin, NULL);

This will disable the line buffering within the stdio library.

> (Of course, you need a second struct termios to memcpy() all the old
> values to be able to restore the previous state which you're expected to
> do.)

If you want to be really sure about restoring the previous state, you
need to install some signal handlers in case the program dies suddenly
(SIGINT, SIGQUIT, etc). If you don't disable SIGTSTP (Ctrl-Z), you
should restore the terminal state on SIGTSTP then re-enable the
changes on SIGCONT.

-- 
Glynn Clements <glynn.clements@virgin.net>

^ permalink raw reply	[flat|nested] 10+ messages in thread

end of thread, other threads:[~2003-06-19 17:39 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2003-06-18  9:58 stdio John T. Williams
2003-06-18 12:02 ` stdio Jan-Benedict Glaw
2003-06-18 12:17 ` stdio Luciano Moreira - igLnx
2003-06-18 13:04 ` stdio Stephen Satchell
2003-06-18 17:45   ` stdio Glynn Clements
2003-06-18 18:30 ` stdio Chris Nanakos
2003-06-19  7:33   ` I'm really starting to dislike stdio John T. Williams
2003-06-19 11:26     ` Jan-Benedict Glaw
2003-06-19 17:39       ` Glynn Clements
2003-06-19 12:56     ` Andrés Roldán

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).