views:

69

answers:

4

Because I'm currently setting up a new server for use, I've been using a lot of command-line programs like curl and wget, and I've noticed that they do something interesting. When run in the Terminal, they print their current progress in place (e.g. 54% will become 55% in place, instead of 55% being printed on the next line - download a large file and you will see what I mean).

I've been wondering how programs can do this. Writing to stdout is nothing new to me, but I'm puzzled at how something like this would work. I've tried writing to stdout, then seeking backwards and writing again; printing backspace characters ('\b'), and printing new things; etc, but nothing seems to work.

Is there no API in Objective-C or C to do this? (C, for instance, has ungetc(), but no unputc()). Are there hacks that can achieve this?
Just something interesting I would like to know more about...

Thanks!

+2  A: 

basically you can do it by something like this:

printf( "progress %3d%%\r", perc );

the \r returns to the start of the same line

Anders K.
That worked great! Thanks!
itaiferber
@itaiferber: As you mention in the original post this technique is a hack.
Martin York
+4  A: 

The most common method is using \r to return to the beginning of the line and rewriting the whole line, but \b should also work. Make sure you're calling fflush(stdout). And don't let the cursor move to a different line, or redrawing will be a lot more of a pain.

R..
Thanks for the tip!
itaiferber
@itaiferber: This is not a reliable technique. Nor is it how the above packages achieve this functionality. See Sedate Alien answer below.
Martin York
@Martin: your comment is wrong. `wget` most certainly does not use curses.
R..
@R.. Nor did I say it was. I just stated that they don't use '\r' or other techniques that are unreliable. I would suggest using a package that can move the cursor using the appropriate control codes for the current terminal being used. One of these packages happens to be ncurses. Though they could read the control characters from the terminal DB that is installed on most (Unix like) machines.
Martin York
+1  A: 

The ncurses project might also be of interest to you. Once you get beyond the simple stuff, you want to be focussing on the core of your app's logic, not its presentation!

GNU ncurses is used by just about every pretty terminal UI application you come across.

Sedate Alien
Thanks for this. This seems like a better, more reliable answer than `\r`.
itaiferber
Using curses just for an updatable status line is insane overkill. Also I don't think you can use curses without taking responsibility for the entire terminal contents (as opposed to just a single line). Do you really want to erase the existing screen contents (other programs' output) or make it impossible to save the output to a file and machine-parse it in a predictable way? It's also *not* how programs like `wget` do it; they simply use `\r`. Martin's comment on my answer appears to just be wrong, and I would strongly recommend against using curses for this purpose.
R..
@R..: Its been a long time since I used curses. But I am sure you do not need to take over the whole screen and there is functionality for building a status line. **BUT** the important point is to use a package the understands that different terminals have different properties and we to reliably control the position of the cursor. ie. We need a package which has some form of termcap DB capabilities. ncurses is such a package (Though ncurses does a lot more aswell). But I am sure with a bit of web-browsing and the key terms an appropriate package can be found.
Martin York
@R..: I wasn't necessarily suggesting that ncurses is ideal for _this_ scenario, but that it might be useful for more advanced UIs. In any case, it seems to have served its purpose as the OP was unaware of the library.
Sedate Alien
If OP were asking about running externals programs connected with a pipe and wasn't aware of `popen`, I would not consider mentioning `popen` a positive thing, because it's a very bad solution to the problem (shell quoting issues, path issues, lack of bidirectionality, ...). Likewise for this OP and curses. By the way, I've never heard of any terminal, much less one of modern relevance, where positioning is possible but `\r` does not work.
R..
@R, I probably should have fleshed out my question a little bit more, but in the end, I really was looking for an `ncurses` type of solution. I only used `wget` as an example (it was the only one I could think of), and what I really meant to do is get something running that resembles an `ncurses` program, with a more advanced UI. Writing a game using `\r` would be a little bit crazy; `ncurses` is a lot more manageable.
itaiferber
A: 

Or S-Lang, which is viewed by many as the successor to ncurses.

Amigable Clark Kant
As a side note ncurses was the replacement for curses. It stands for NEW-Curses (I think).
Martin York