ЭЛЕКТРОННАЯ БИБЛИОТЕКА КОАПП
Сборники Художественной, Технической, Справочной, Английской, Нормативной, Исторической, и др. литературы.



11.6 Changing Defaults for Formats

We have often referred to the default for this or that. Well, Perl provides a way to override the defaults for just about every step. Let's talk about these.

11.6.1 Using select to Change the Filehandle

Back when we talked about print, in Chapter 6, Basic I/O, we mentioned that print and print STDOUT were identical, because STDOUT was the default for print. Not quite. The real default for print (and write, and a few other operations we'll get to in a moment) is an odd notion called the currently selected filehandle.

The currently selected filehandle starts out as STDOUT - which makes it easy to print things on the standard output. However, you can change the currently selected filehandle with the select function. This function takes a single filehandle (or a scalar variable containing the name of a filehandle) as an argument. After the currently selected filehandle is changed, it affects all future operations that depend on the currently selected filehandle. For example:

print "hello world\n";      # like print STDOUT "hello world\n";
select (LOGFILE);           # select a new filehandle
print "howdy, world\n";     # like print LOGFILE "howdy, world\n";
print "more for the log\n"; # more for LOGFILE
select (STDOUT);            # re-select STDOUT
print "back to stdout\n";   # this goes to standard output

Note that the select operation is sticky - after you've selected a new handle, it stays in effect until the next select.

So, a better definition for STDOUT with respect to print and write is that STDOUT is the default currently selected handle, or the default default handle.

Subroutines may find a need to change the currently selected filehandle. However, you would be shocked if you called a subroutine and then found out that all of your carefully crafted text lines were going into some bit bucket because the subroutine changed the currently selected filehandle without restoring it. So what's a well-behaved subroutine to do? If the subroutine knows that the current handle is STDOUT, the subroutine can restore the selected handle with code similar to that given earlier. However, what if the caller of the subroutine had already changed the selected filehandle?

The return value from select is a string containing the name of the previously selected handle. You can capture this value to restore the previously selected filehandle later, using code like this:

$oldhandle = select LOGFILE;
print "this goes to LOGFILE\n";
select ($oldhandle); # restore the previous handle

Yes, for these examples, putting LOGFILE explicitly as the filehandle for the print is an easier method, but some operations require the currently selected filehandle to change, as we will soon see.

11.6.2 Changing the Format Name

The default format name for a particular filehandle is the same as the filehandle. However, you can change this name for the currently selected filehandle by setting the new format name into a special variable called $~. You can also examine the value of the variable to see what the current format is for the currently selected filehandle.

For example, to use the ADDRESSLABEL format on STDOUT, simply use the following:

$~ = "ADDRESSLABEL";

But what if you want to set the format for the REPORT filehandle to SUMMARY? Just a few steps to do it here:

$oldhandle = select REPORT;
$~ = "SUMMARY";
select ($oldhandle);

The next time we say:

write (REPORT);

we get text out on the REPORT filehandle in the SUMMARY format.

Note that we saved the previous handle into a scalar variable and then restored it later. This maneuver is good programming practice. In fact, in production code, we probably would have handled the previous one-line example similarly and not assumed that STDOUT was the default handle.

By setting the current format for a particular filehandle, you can interleave many different formats in a single report.

11.6.3 Changing the Top-of-Page Format Name

Just as we can change the name of the format for a particular filehandle by setting the $~ variable, we can change the top-of-page format by setting the $^ variable. This variable holds the name of the top-of-page format for the currently selected filehandle and is read/write, meaning that you can examine its value to see the current format name, and you can change it by assigning to it.

11.6.4 Changing the Page Length

If a top-of-page format is defined, the page length becomes important. By default, the page length is 60 lines; that is, when a write won't fit by the end of line 60, the top-of-page format is invoked automatically before printing the text.

Sometimes 60 lines isn't right. You can change this by setting the $= variable. This variable holds the current page length for the currently selected filehandle. Once again, to change it for a filehandle other than STDOUT (the default currently selected filehandle), you'll need to use the select() operator. Here's how to change the LOGFILE filehandle to have 30-line pages:

$old = select LOGFILE; # select LOGFILE and save old handle
$= = 30;
select $old;

Changing the page length won't have any effect until the next time the top-of-page format is invoked. If you set it before any text is output to a filehandle through a format, it'll work just fine because the top-of-page format is invoked immediately at the first write.

11.6.5 Changing the Position on the Page

If you print your own text to a filehandle, it messes up the page-position line count because Perl isn't counting lines for anything but a write. If you want to let Perl know that you've output a few extra lines, you can adjust Perl's internal line count by altering the $- variable. This variable contains the number of lines left on the current page on the currently selected filehandle. Each write decrements the lines remaining by the lines actually output. When this count reaches zero, the top-of-page format is invoked, and the value of $- is then copied from $= (the page length).

For example, to tell Perl that you've sent an extra line to STDOUT, do something like this:

write; # invoke STDOUT format on STDOUT
...;
print "An extra line... oops!\n"; # this goes to STDOUT
$- --; # decrement $- to indicate non-write line went to STDOUT
...;
write; # this will still work, taking extra line into account

At the beginning of the program, $- is set to zero for each filehandle. This ensures that the top-of-page format will be the first thing invoked for each filehandle upon the first write.