I decided I would like to be able to type LINE X SOMEFILE.ADA and see that line on the screen. The more I thought about it, the more I realized I really wanted to see a few lines before and after line X. So, I wrote the Line program shown in Listings 63 and 64.
Although the Line program was written in response to a specific need (to display lines containing errors), it isn't limited to that single use. You can use it to browse through any file for any reason.
My first reaction was that the file name should be the first argument and the line number should be the second one. This makes sense from a programmer's point of view because the file has to be opened before the program can start looking for a particular line. It also seemed consistent because More and Write both have filenames immediately following the command.
I wrote the Extract routine to take the file name first, used the program for a while, and found I kept making mistakes. If I wanted to see line 15 of SOMEFILE.ADA, I naturally typed LINE 15 SOMEFILE.ADA. It seemed wrong to type LINE SOMEFILE.ADA 15. (Since it's usually right to not split an infinitive, analogy suggests that I shouldn't separate 15 from LINE.) From a user's point of view, it makes more sense from a user's point of view to put the line number first, so I changed the order in Extract.
The user might respond to this error message with a respectful genuflection, and say, "Oh, I'm so sorry. Please forgive me. I promise never to make that mistake again." Users like that may exist, but I've never found one. Most users will say, "If you're so darn smart, and know that the arguments are reversed, why don't you just do what I want?" The point is well taken. If a program is smart enough to recognize the error, and can tell the user exactly how to correct it, can't it just as well be smart enough to fix the error itself?
This kind of tolerance is almost unknown in user interfaces, but perhaps the Line program may start a trend. Instead of insulting the user, it simply complies with any poorly stated command. If the user enters the two arguments in the correct order, it works. If the user enters the two arguments backwards, it works. If the user forgets to enter the file name, it asks for the file name. If the user forgets to enter the line number, it asks for the line number. If the user doesn't enter either, it asks for both. There's no need to be nasty when its so easy to be nice.
The Alsys and DEC versions of Get_Command_Line are built on general routines that return the whole command line. Alsys and DEC didn't make any assumptions about how anyone would want to use the command line. They just give you the command line and let you do whatever you want with it.
Meridian assumed that anyone who wants the command line will want to break it down into individual arguments, so they tried to do the programmer a favor and split it apart for him. Their ARG package tells you how many arguments there are, and passes an array of arguments back. That's really handy if that's exactly what you want to do. If it isn't then it is clumsy.
I've written a routine that doesn't appear in this book (because it doesn't teach any new lessons) called Search that searches a file for a text string. It is invoked by the command SEARCH FILENAME.EXT "A STRING WHICH MAY CONTAIN PUNCTUATION, SPACES, AND WHO KNOWS WHAT ELSE!". The Meridian ARG package returns this as 13 individual arguments, but there are really only two (FILENAME.EXT and the text string). I have to go to the trouble to put together the things that Meridian has taken apart.
That's not a terrible ordeal. Listing 65 shows how to do it. It's inefficient for ARG to take apart the command string and then make Get_Command_Line put it back together so Line.Extract can take it apart again, but that's the price you pay for portability if you make your utility routines too specific.