Jez Higgins

Freelance software grandad
software created
extended or repaired


Follow me on Twitter
My code on GitHub
Talks & Presentations

Hire me
Contact

Older posts are available in the archive or through tags.

Feed

Thursday 30 April 2020 The Forest Road Reader, No 2.46 : STinC++ - print

STinC++ rewrites the programs in Software Tools in Pascal using C++

The previous program, concat, was a simple example of taking an indeterminate number of inputs and generating one output. That your own machine undoubtedly has cat or its moral equivalent installed shows the enduring utility of combining files, unformatted, into a single stream.

Similar styles of program, such as less, take those multiple inputs and produce some kind of formatted output. Kernighan and Plauger’s next program, print, continues the many-in/one-out pattern and adds just a smattering of formatting.

PROGRAM

print print files with headings

USAGE

print [ file …​ ]

FUNCTION

print copies each of its argument files in turn to its output, inserting page headers and footer and filling the last page of each file to full length. A header consists of two blank lines, a line giving the filename and page number, and two more blank lines; a footer consists of two blank lines. Pages for each file are numbered starting at one. If no arguments are specified, print prints its standard input; the file name is null.
The text of each file is unmodified - no attempt is made to fold long lines or expands tabs to spaces.

EXAMPLE

print print.p fprint.p

My implementation is probably much as you would imagine. Loop on each file, reading a line at a time, keeping count of lines as we go. If we’re at the top of a page, print the header. If we’re at the bottom, print the footer. When we run out of lines to read, pad with blanks until we hit the bottom of the page.

My initial implementation matched almost exactly with Kernighan and Plauger’s. The only real difference was that I calculated the number of lines in the header and footer from their implementations, rather than using manifest constants. But there it was, a loop, some input, some output, a bit of incrementing, some conditionals, just as Kernighan and Plauger had 40 years previously -

print.cpp - initial implementation
  int print(
    std::string const& filename,
    std::istream& input,
    std::ostream& output,
    size_t path_length
  ) {
    size_t page_count = 0;
    size_t line_count = 0;
    size_t const last_line = path_length - footer_lines;

    while(input && !input.eof()) {
      if (line_count == 0) {
        header(filename, ++page_count, output);
        line_count += header_lines;
      }

      std::string line = getline(input);
      output << line << '\n';
      ++line_count;

      if (line_count == last_line) {
        footer(output);
        line_count = 0;
      }
    }

    if (line_count != 0) {
      for ( ; line_count != last_line; ++line_count)
        output << '\n';
      footer(output);
    }

    return page_count;
  } // print

Since I’ve already described what it does, you can quite easily see which bit does what and it’s, you know, fine. But it’s a bit of long, and it’s kind of boring.

So late on, after I’d started drafting what you’re reading now, I had another go at it, gathering up the bits of state into a little class, and now the file printing loop looks like this.

print.cpp
  class page_printer {
    // ...

    size_t print() {
      while(input_available()) {
        if (at_page_start())
          print_header();

        print_line();

        if (at_last_line())
          print_footer();
      } // while ...

      pad_to_page_end();

      return page_count_;
    } // print

    // ...
  };

Better.

Source code

Source code for this program, indeed the whole project, is available in the stiX GitHub repository. print is fourth program of Chapter 3.


Tagged code, and software-tools-in-c++


Jez Higgins

Freelance software grandad
software created
extended or repaired

Follow me on Twitter
My code on GitHub
Talks & Presentations

Hire me
Contact

Older posts are available in the archive or through tags.

Feed