############################################################################ # # File: printcol.icn # # Subject: Procedure to format columnar data # # Author: Robert J. Alexander # # Date: August 14, 1996 # ############################################################################ # # This file is in the public domain. # ############################################################################ # # This procedure deals with with the problem of printing tabular # data where the total width of items to be printed is wider than # the page. Simply allowing the data to wrap to additional lines # often produces marginally readable output. This procedure facil- # itates printing such groups of data as vertical columns down the # page length, instead of as horizontal rows across the page. That # way many, many fields can be printed neatly. The programming of # such a transformation can be a nuisance. This procedure does # much of the work for you, like deciding how many items can fit # across the page width and ensuring that entire items will be # printed on the same page without page breaks (if that service is # requested). # ############################################################################ # # For example, suppose we have a list of records we would like # to print. The record is defined as: # # record rec(item1,item2,item3,...) # # Also suppose that lines such as # # Field 1 Field 2 Field 3 ... # ------- ------- ------- --- # Record 1 item1 item2 item3 ... # Record 2 item1 item2 item3 ... # # are too long to print across the page. This procedure will print # them as: # # TITLE # ===== # Record 1 Record 2 ... # -------- -------- --- # Field 1 item1 item1 ... # Field 2 item2 item2 ... # Field 3 item3 item3 ... # # The arguments are: # # items: a co-expression that produces a sequence of # items (usually structured data objects, but not # necessarily) for which data is to be printed. # # fields: a list of procedures to produce the field's # data. Each procedure takes two arguments. The # procedure's action depends upon what is passed # in the first argument: # # header Produces the row heading string to be used # for that field (the field name). # # width Produces the maximum field width that can # be produced (including the column header). # # Other Produces the field value string for the # item passed as the argument. # # The second argument is arbitrary data from the procedures # with each invocation. The data returned by the first func- # tion on the list is used as a column heading string (the # item name). # # title: optional. # # # pagelength: if null (omitted) page breaks are ignored. # # linelength: default 80. # # auxdata: auxiliary arbitrary data to be passed to the field # procedures -- see `fields', above. # ############################################################################ procedure printcol(items,fields,title,pagelength,linelength,auxdata) local maxwidth,maxhead,groups,columns,itemlist,cont,f,p,underline, hfield /linelength := 80 /pagelength := 30000 /title := "" # # Compute the maximum field width (so we know the column spacing) and # the maximum header width (so we know how much space to leave on the # left for headings. # maxwidth := maxhead := -1 cont := "" every maxwidth <:= (!fields)("width",auxdata) hfield := get(fields) every maxhead <:= *(!fields)("header",auxdata) columns := (linelength - maxhead) / (maxwidth + 1) groups := pagelength / (6 + *fields) # # Loop to print groups of data. # repeat { if pagelength < 30000 then writes("\f") # # Loop to print data of a group (a page's worth). # every 1 to groups do { # # Collect the items to be output in this group. A group is the number # of columns that can fit across the page. # itemlist := [] every 1 to columns do put(itemlist,@items) | break if *itemlist = 0 then break break # # Print a title and the column headings. # write(repl("=",*write("\n",title || cont))) cont := " (continued)" writes(underline := left("",maxhead)) every f := hfield(!itemlist,auxdata) do { p := if *f < maxwidth then center else left writes(" ",p(f,maxwidth)) underline ||:= " " || p(repl("-",*f),maxwidth) } write("\n",underline) # # Print the fields. # every f := !fields do { writes(right(f("header",auxdata),maxhead)) every writes(" ",center(f(!itemlist,auxdata),maxwidth)) write() } } # End of loop to print groups. } # End of loop to print all items. return end