A program like 'more'

I’ve been programming (in C) in Unix for a few months, and it occurred to me that nothing I’ve learned so far allows me to write a program that emulates a small part of the functionality of the basic program ‘more’ that lives on every Unix workstation.

Specifically, I don’t know how to handle input and output like more does. If you’re reading this, you probably know that the purpose of more is to display the contents of a text file in a convenient way. There are various ways to call more from a shell. When invoked as

more < sometextfile

or

someothercommand | more

more will, as one would expect, display the contents of sometextfile or the output of someothercommand in a convenient way. However, unlike the programs I know how to write, more still accepts commands interactively from the keyboard, even in such cases, where its “standard input” is supposedly redirected.

On the other hand,

more sometextfile

has the exact same effect as

more < sometextfile.

Remarkably, more does not read lines of input from the keyboard and display them. However, it does accept commands interactively from the keyboard in the exact same way as it does when its input is redirected. In this way, the way more uses its “standard input” is fundamentally different depending on whether the shell has redirected its standard input or not.

Moreover,

more sometextfile | someothercommand

is fundamentally different from the above cases: in this case, more does not use keyboard input at all.

The thing that is simply beyond me right now is that the program more is able to respond differently based on where the shell connects its input and output; I don’t even know how to tell, from within a process, whether the process’s input/output have been redirected by the shell. And secondly, no matter where the shell connects the input of more, more retains the ability to accept commands directly from the keyboard.

So how can a program tell where its standard input is coming from and where its standard output is going? And how can a program take commands directly from the keyboard if the shell has redirected its standard input? If anything isn’t clear, I’d be happy to clarify.

(P.S.: Thanks to those who responded to my previous GQ’s, A Proof of the Riemann Hypothesis?, and General Animalian Color Vision.)

You’re thinking wrong, more isn’t responding differently depending on whether input and output are redirected, it’s responding differently whether or not it’s got a filename for a parameter.

both the < and the | redirect more’s stdin, the < from a file and the | from a command. More has no arguements in this case, so it assumes it should start reading from stdin and doing its thing.

When you say “more sometextfile”, more assumes by the arguement count that it should open sometextfile and do its thing on that.

to really blow your mind, just run “more”.

-lv

The isatty function will tell you if stdin is connected to a terminal.

LordVor, what you say is prima facie reasonable, but you can’t be right. Sorry, I didn’t mention that the command

more

sends an error message to stderr:

Usage: more [-cdflrsuw] [-lines] [+linenumber] [+/pattern] [filename …].

I don’t know if your version of more does the same.

Mr2001, thanks for isatty; it does indeed do what you say. One down, one to go. I don’t suppose you know how to access the keyboard without having to use standard input?

I suggest checking the source code. I couldn’t find the source for ‘more’, though I’m sure it’s out there, so here is the source for ‘less’, which works mostly the same.

Here’s what appears to be a Japanes langauge version of more:
http://www.kyoto-su.ac.jp/circle/mics/Docs/unix/command/FILE/more.c

I’m still looking for an english version.

http://cvs.kerneli.org/util-linux/text-utils/more.c?annotate=1.1

Well, that last would appear to have been crap.
Here’s the real thing:
http://www.mit.edu/afs/athena/astaff/reference/4.4lite/usr/src/old/more/more.c

I’ll assume that you were referring to your earlier post, and not to mine. :slight_smile:

Yup. Sorry. :slight_smile:

Usually, in any UNIX variant, if a program explicity opens /dev/tty it will read from the current TTY (the “keyboard,” whether that is a physically-connected keyboard at the console, a serial port, a telnet/ssh session, whatever) and allow it to interact with the user directly, regardless of where stdin/stdout are pointing.

Another fun fact is that many UNIX programs will behave differently depending on whether stdin is a tty or not. They’ll check the result of the isatty() call and change their buffering mode accordingly. If they’re connected to a TTY they’ll default to “line buffered” mode (asking the kernel to send them a single line of text at a time, which is usually best for interacting with a terminal) whereas they’ll default to either raw (one character at a time) or some sort of buffered mode (a “block” at a time, with the block size being some arbitrarily-sized chunk of data, which is better for dealing with “bulk” data, or data that may be in binary format).

good point. I tested my theory under HP-UX, which does indeed pipe input from the keyboard into more’s display engine when you just type in “more”, no error message.

Mort’s link to source code seems to use an ioctl instead of the isatty() test, but still uses the argc to see if it should read a file or print the error if there’s no file and no tty input.

opening /dev/tty solves the real question I had, which was “If more’s stdin is redirected, then how can more get commands from the keyboard?”

-lv

Thanks, pestie, that’s exactly what I need. Unfortunately, you were too late; I downloaded the source code for ‘less’ last night and a little while ago I figured out the bit about /dev/tty. Also, apparently you can read input from standard error (the version of less Mr2001 linked to will first try opening /dev/tty and on failure will use standard error for keyboard input). By experimenting, I think that this will work as long as you use the low-level function ‘read’ to do it and standard error is not being redirected. I’m having trouble finding doumentation on using input from stderr, but it seems to work on this machine. Moreover,

more sometextfile 2>> junk

Does not behave as expected. It displays one screenful of sometextfile, up to the point where it would normally say “MORE” and wait for input, but instead it just returns to the shell after the one screenful. This leads me to believe that more is trying to read keyboard input from the standard error stream, but the read is failing because stderr is being redirected.

less sometextfile 2>> junk

Also doesn’t behave properly. The keyboard input becomes echoed and buffered and the output is messed up, but the program is basically able to display the entire file.

Thanks to everyone who responded. Now I basically know what I wanted to know. The source code for ‘more’ will be useful.

I realize this is an old thread, but I’ve read through it twice and I think there are some basic misconceptions that need to be cleared up(just in case someone searches, you know?).

Redirection is handled by the shell that you are using, not by the program you are calling. All the program needs to do is to read stdin or write to stdout to be able to work with redirection. In the case of “more”, it will read stdin if there is no file argument (although, as The Weak Force found out, some versions will not accept input from the terminal)

Check the documentation for the specifics of how redirection works for your shell. I know there are minor variations in implementation; however, here are some basics that work in ksh and csh:

> file send standard out to a file
< file Use a file as standard input
command | command Take the standard out put from the first command and process it with the second command.

If I understand the last post by The Weak Force, more is not the command you want to use. It looks like you are trying to append one file to the end of another one. The command cat will write the contents of desired file to standard output without interaction and can be then be redirected with >> to append to another file.