{Begin SubSec PRINTOUT} {Title PRINTOUT} {Text {index PRINTOUT (CLISP word)} {Tag PRINTOUT} Interlisp provides many facilities for controlling the format of printed output. By executing various sequences of {fn PRIN1}, {fn PRIN2}, {fn TAB}, {fn TERPRI}, {fn SPACES}, {fn PRINTNUM}, and {fn PRINTDEF}, almost any effect can be achieved. {lisp PRINTOUT} implements a compact language for specifying complicated sequences of these elementary printing functions. It makes fancy output formats easy to design and simple to program. {lisp PRINTOUT} is a CLISP word (like {lisp for} and {lisp if}) for interpreting a special printing language in which the user can describe the kinds of printing desired. The description is translated by {fn DWIMIFY} to the appropriate sequence of {fn PRIN1}, {fn TAB}, etc., before it is evaluated or compiled. {lisp PRINTOUT} printing descriptions have the following general form: {lispcode (PRINTOUT {arg FILE} {arg PRINTCOM{sub 1}} {arg PRINTCOM{sub 2}} {ellipsis} {arg PRINTCOM{sub N}})} {arg FILE} is evaluated to obtain the name of the file to which the output from this specification is directed. The {lisp PRINTOUT} commands are strung together, one after the other without punctuation, after {arg FILE}. Some commands occupy a single position in this list, but many commands expect to find arguments following the command name in the list. The commands fall into several logical groups: one set deals with horizontal and vertical spacing, another group provides controls for certain formatting capabilities (font changes and subscripting), while a third set is concerned with various ways of actually printing items. Finally, there is a command that permits escaping to a simple Lisp evaluation in the middle of a {lisp PRINTOUT} form. The various commands are described below. The following examples give a general flavor of how {lisp PRINTOUT} is used: Example 1: Suppose the user wanted to print out on the terminal the values of three variables, {lisp X}, {lisp Y}, and {lisp Z}, separated by spaces and followed by a carriage return. This could be done by: {lispcode (PRIN1 X T) (SPACES 1 T) (PRIN1 Y T) (SPACES 1 T) (PRIN1 Z T) (TERPRI T)} or by the more concise {lisp PRINTOUT} form: {lispcode (PRINTOUT T X , Y , Z T)} Here the first {lisp T} specifies output to the terminal, the commas cause single spaces to be printed, and the final {lisp T} specifies a {fn TERPRI}. The variable names are not recognized as special {lisp PRINTOUT} commands, so they are printed using {fn PRIN1} by default. Example 2: Suppose the values of {lisp X} and {lisp Y} are to be pretty-printed lined up at position 10, preceded by identifying strings. If the output is to go to the primary output file, the user could write either: {lispcode (PRIN1 "X =") (PRINTDEF X 10 T) (TERPRI ) (PRIN1 "Y =") (PRINTDEF Y 10 T) (TERPRI)} or the equivalent: {lispcode (PRINTOUT NIL "X =" 10 .PPV X T "Y =" 10 .PPV Y T)} Since strings are not recognized as special commands, {lisp "X ="} is also printed with {fn PRIN1} by default. The positive integer means {fn TAB} to position 10, where the {lisp .PPV} command causes the value of {lisp X} to be prettyprinted as a variable. By convention, special atoms used as {lisp PRINTOUT} commands are prefixed with a period. The {lisp T} causes a carriage return, so the {lisp Y} information is printed on the next line. Example 3. As a final example, suppose that the value of {lisp X} is an integer and the value of {lisp Y} is a floating-point number. {lisp X} is to be printed right-flushed in a field of width 5 beginning at position 15, and {lisp Y} is to be printed in a field of width 10 also starting at position 15 with 2 places to the right of the decimal point. Furthermore, suppose that the variable names are to appear in the font named {lisp BOLDFONT} and the values in font {lisp SMALLFONT}. The program in ordinary Lisp that would accomplish these effects is too complicated to include here. With {lisp PRINTOUT}, one could write: {lispcode (PRINTOUT NIL .FONT BOLDFONT "X =" 15 .FONT SMALLFONT .I5 X T .FONT BOLDFONT "Y =" 15 .FONT SMALLFONT .F10.2 Y T .FONT BOLDFONT)} The {lisp .FONT} commands do whatever is necessary to change the font on a multi-font output device. The {lisp .I5} command sets up a {lisp FIX} format for a call to the function {fn PRINTNUM} ({PageRef Fn PRINTNUM}) to print {lisp X} in the desired format. The {lisp .F10.2} specifies a {lisp FLOAT} format for {fn PRINTNUM}. {Begin SubSec Horizontal Spacing Commands} {Title Horizontal Spacing Commands} {Text The horizontal spacing commands provide convenient ways of calling {fn TAB} and {fn SPACES}. In the following descriptions, {arg N} stands for a literal positive integer. {Begin LabeledList horizontal spacing commands} {Label {arg N}} {Item {indexX {Name N} {Type (PRINTOUT command)} {Text {arg N} ({arg N} a number)} }Used for absolute spacing. It results in a {fn TAB} to position {arg N} (literally, a {lisp (TAB {arg N})}). If the line is currently at position {arg N} or beyond, the file will be positioned at position {arg N} on the next line. } {Label {lisp .TAB {arg POS}}} {Item {index .TAB (PRINTOUT command)}Specifies {fn TAB} to position (the value of) {arg POS}. This is one of several commands whose effect could be achieved by simply escaping to Lisp, and executing the corresponding form. It is provided as a separate command so that the {lisp PRINTOUT} form is more concise and is prettyprinted more compactly. Note that {lisp .TAB {arg N}} and {arg N}, where {arg N} is an integer, are equivalent. } {Label {lisp .TAB0 {arg POS}}} {Item {index .TAB0 (PRINTOUT command)}Like {lisp .TAB} except that it can result in zero spaces (i.e. the call to {fn TAB} specifies {arg MINSPACES}=0). } {Label {lisp -{arg N}}} {Item {indexX {Name N} {Type (PRINTOUT command)} {Text -{arg N} ({arg N} a number)} }Negative integers indicate relative (as opposed to absolute) spacing. Translates as {lisp (SPACES |{arg N}|)}. } {Label {lisp ,} {lisp ,,} {lisp ,,,}} {Item {index , (PRINTOUT command)}Provides a short-hand way of specifying 1, 2 or 3 spaces, i.e., these commands are equivalent to {lisp -1}, {lisp -2}, and {lisp -3}, respectively. } {Label {lisp .SP {arg DISTANCE}}} {Item {index .SP (PRINTOUT command)}Translates as {lisp (SPACES {arg DISTANCE})}. Note that {lisp .SP {arg N}} and {lisp -{arg N}}, where {arg N} is an integer, are equivalent. } {Label {lisp .RESET}} {Item {index .RESET (PRINTOUT command)}Resets the current line by causing a carriage-return to be printed without a line-feed. Useful for overprinting, or for regaining control of a line on which characters have been printed in a variable pitched font. } {End LabeledList horizontal spacing commands} }{End SubSec Horizontal Spacing Commands} {Begin SubSec Vertical Spacing Commands} {Title Vertical Spacing Commands} {Text Vertical spacing is obtained by calling {fn TERPRI} or printing form-feeds. The relevant commands are: {Begin LabeledList Vertical spacing commands} {Label {lisp T}} {Item {index T (PRINTOUT command)}Translates as {lisp (TERPRI)}. This command is functionally equivalent to the integer command {lisp 0}; they both move to position 0 (= column 1) of the next line. To print the letter {lisp T}, use the string {lisp "T"}. } {Label {lisp .SKIP {arg LINES}}} {Item {index .SKIP (PRINTOUT command)}Equivalent to a sequence of {arg LINES} {lisp (TERPRI)}'s. The {lisp .SKIP} command allows for skipping large constant distances and for computing the distance to be skipped. } {Label {lisp .PAGE}} {Item {index .PAGE (PRINTOUT command)}Puts a form-feed (control-L){index control-L} out on the file. Care is taken to make sure that Interlisp's view of the current line position is correctly updated. } {End LabeledList Vertical spacing commands} }{End SubSec Vertical Spacing Commands} {Begin SubSec Special Formatting Controls} {Title Special Formatting Controls} {Text There are a small number of commands for invoking some of the formatting capabilities of multi-font output devices. The available commands are: {Begin LabeledList Special Formatting Commands} {Label {lisp .FONT {arg FONTSPEC}}} {Item {index .FONT (PRINTOUT command)}Puts out a control sequence that causes a change to font {arg FONTSPEC} (the association between {arg FONTSPEC} and a specific font must be defined in the user's font profile, as described in {PageRef Tag FontProfile}). {arg FONTSPEC} may be a font-name variable or an expression that evaluates to the value of a font-name variable. {arg FONTSPEC} may also be a positive integer {arg N}, which is taken as an abbreviated reference to the font named {lisp FONT{arg N}} (e.g. 1 => {lisp FONT1}). } {Label {lisp .SUP}} {Item {index .SUP (PRINTOUT command)}Specifies superscripting. All subsequent characters are printed above the base of the current line. Note that this is absolute, not relative: a {lisp .SUP} following a {lisp .SUP} is a no-op. } {Label {lisp .SUB}} {Item {index .SUB (PRINTOUT command)}Specifies subscripting. Subsequent printing is below the base of the current line. As with superscripting, the effect is absolute. } {Label {lisp .BASE}} {Item {index .BASE (PRINTOUT command)}Moves printing back to the base of the current line. Un-does a previous {lisp .SUP} or {lisp .SUB}; a no-op, if printing is currently at the base. } {End LabeledList Special Formatting Commands} }{End SubSec Special Formatting Controls} {Begin SubSec Printing Specifications} {Title Printing Specifications} {Text The value of any expression in a {lisp PRINTOUT} form that is not recognized as a command itself or as a command argument is printed using {fn PRIN1} by default. For example, title strings can be printed by simply including the string as a separate {lisp PRINTOUT} command, and the values of variables and forms can be printed in much the same way. Note that a literal integer, say 51, cannot be printed by including it as a command, since it would be interpreted as a {lisp TAB}; the desired effect can be obtained by using instead the string specification "51", or the form {lisp (QUOTE 51)}. For those instances when {fn PRIN1} is not appropriate, e.g., {fn PRIN2} is required, or a list structures must be prettyprinted, the following commands are available: {Begin LabeledList Printing Specifications} {Label {lisp .P2 {arg THING}}} {Item {index .P2 (PRINTOUT command)}Causes {arg THING} to be printed using {fn PRIN2}; translates as {lisp (PRIN2 {arg THING})}. } {Label {lisp .PPF {arg THING}}} {Item {index .PPF (PRINTOUT command)}Causes {arg THING} to be prettyprinted at the current line position via {fn PRINTDEF} ({PageRef Fn PRINTDEF}). The call to {fn PRINTDEF} specifies that {arg THING} is to be printed as if it were part of a function definition. That is, {fn SELECTQ}, {fn PROG}, etc., receive special treatment. } {Label {lisp .PPV {arg THING}}} {Item {index .PPV (PRINTOUT command)}Prettyprints {arg THING} as a variable; no special interpretation is given to {fn SELECTQ}, {fn PROG}, etc. } {Label {lisp .PPFTL {arg THING}}} {Item {index .PPFTL (PRINTOUT command)}Like {lisp .PPF}, but prettyprints {arg THING} as a {it tail}, that is, without the initial and final parentheses if it is a list. Useful for prettyprinting sub-lists of a list whose other elements are formatted with other commands. } {Label {lisp .PPVTL {arg THING}}} {Item {index .PPVTL (PRINTOUT command)}Like {lisp .PPV}, but prettyprints {arg THING} as a tail. } {End LabeledList Printing Specifications} {Begin SubSec Paragraph Format} {Title Paragraph Format} {Text Interlisp's prettyprint routines are designed to display the structure of expressions, but they are not really suitable for formatting unstructured text. If a list is to be printed as a textual paragraph, its internal structure is less important than controlling its left and right margins, and the indentation of its first line. The {lisp .PARA} and {lisp .PARA2} commands allow these parameters to be conveniently specified. {Begin LabeledList Paragraph Format} {Label {lisp .PARA {arg LMARG} {arg RMARG} {arg LIST}}} {Item {index .PARA (PRINTOUT command)}Prints {arg LIST} in paragraph format, using {fn PRIN1}. Translates as {lisp (PRINTPARA {arg LMARG} {arg RMARG} {arg LIST})} (see {PageRef Fn PRINTPARA}). Example: {lisp (PRINTOUT T 10 .PARA 5 -5 LST)} will print the elements of {lisp LST} as a paragraph with left margin at 5, right margin at {lisp (LINELENGTH)}-5, and the first line indented to 10. } {label {lisp .PARA2 {arg LMARG} {arg RMARG} {arg LIST}}} {Item {index .PARA2 (PRINTOUT command)}Print as paragraph using {fn PRIN2} instead of {fn PRIN1}. Translates as {lisp (PRINTPARA {arg LMARG} {arg RMARG} {arg LIST} T)}. } {End LabeledList Paragraph Format} }{End SubSec Paragraph Format} {Begin SubSec Right-Flushing} {Title Right-Flushing} {Text Two commands are provided for printing simple expressions flushed-right against a specified line position, using the function {fn FLUSHRIGHT} ({PageRef Fn FLUSHRIGHT}). They take into account the current position, the number of characters in the print-name of the expression, and the position the expression is to be flush against, and then print the appropriate number of spaces to achieve the desired effect. Note that this might entail going to a new line before printing. Note also that right-flushing of expressions longer than a line (e.g. a large list) makes little sense, and the appearance of the output is not guaranteed. {Begin LabeledList Right-Flushing} {Label {lisp .FR {arg POS} {arg EXPR}}} {Item {index .FR (PRINTOUT command)}Flush-right using {fn PRIN1}. The value of {arg POS} determines the position that the right end of {arg EXPR} will line up at. As with the horizontal spacing commands, a negative position number means {lisp |{arg POS}|} columns from the current position, a positive number specifies the position absolutely. {arg POS}=0 specifies the right-margin, i.e. is interpreted as {lisp (LINELENGTH)}. } {label {lisp .FR2 {arg POS} {arg EXPR}}} {Item {index .FR2 (PRINTOUT command)}Flush-right using {fn PRIN2} instead of {fn PRIN1}. } {End LabeledList Right-Flushing} }{End SubSec Right-Flushing} {Begin SubSec Centering} {Title Centering} {Text Commands for centering simple expressions between the current line position and another specified position are also available. As with right flushing, centering of large expressions is not guaranteed. {Begin LabeledList Centering} {Label {lisp .CENTER {arg POS} {arg EXPR}}} {Item {index .CENTER (PRINTOUT command)}Centers {arg EXPR} between the current line position and the position specified by the value of {arg POS}. A positive {arg POS} is an absolute position number, a negative {arg POS} specifies a position relative to the current position, and 0 indicates the right-margin. Uses {fn PRIN1} for printing. } {label {lisp .CENTER2 {arg POS} {arg EXPR}}} {Item {index .CENTER2 (PRINTOUT command)}Centers using {fn PRIN2} instead of {fn PRIN1}. } {End LabeledList Centering} }{End SubSec Centering} {Begin SubSec Numbering} {Title Numbering} {Text The following commands provide FORTRAN-like formatting capabilities for integer and floating-point numbers. Each command specifies a printing format and a number to be printed. The format specification translates into a format-list for the function {fn PRINTNUM} (see {PageRef Fn PRINTNUM}). {Begin LabeledList Numbering} {Label {lisp .I{arg FORMAT} {arg NUMBER}}} {Item {index .I (PRINTOUT command)}Specifies integer printing. Translates as a call to the function {fn PRINTNUM} with a {lisp FIX} format-list constructed from {arg FORMAT}. The atomic format is broken apart at internal periods to form the format-list. For example, {lisp .I5.-8.T} yields the format-list {lisp (FIX 5 -8 T)}, and the command sequence {lisp (PRINTOUT T .I5.-8.T FOO)} will translate as {lisp (PRINTNUM '(FIX 5 -8 T) FOO)}. It will cause the value of {lisp FOO} to be printed with radix -8 right-flushed in a field of width 5, with 0's used for padding on the left. Internal {lisp NIL}'s may be omitted, e.g. the commands {lisp .I5..T} and {lisp .I5.NIL.T} are equivalent. } {Label {lisp .F{arg FORMAT} {arg NUMBER}}} {Item {index .F (PRINTOUT command)}Specifies floating-number printing. Like the {lisp .I} format command, except translates with a {lisp FLOAT} format-list. } {Label {lisp .N {arg FORMAT} {arg NUMBER}}} {Item {index .N (PRINTOUT command)}The {lisp .I} and {lisp .F} commands specify calls to {fn PRINTNUM} with quoted format specifications. The {lisp .N} command translates as {lisp (PRINTNUM {arg FORMAT} {arg NUMBER})}, i.e., it permits the format to be the value of some expression. Note that, unlike the {lisp .I} and {lisp .F} commands, {arg FORMAT} is a separate element in the command list, not part of an atom beginning with {lisp .N}. } {End LabeledList Numbering} }{End SubSec Numbering} }{End SubSec Printing Specifications} {Begin SubSec Escaping to LISP} {Title Escaping to LISP} {Text There are many reasons for taking control away from {lisp PRINTOUT} in the middle of a long printing expression. Common situations involve temporary changes to system printing parameters (e.g. {fn LINELENGTH}), conditional printing (e.g. print {lisp FOO} only if {lisp FIE} is {lisp T}), or lower-level iterative printing within a higher-level print specification. {Begin LabeledList Escaping to LISP} {Label {lisp # {arg FORM}}} {Item {index # (PRINTOUT command)}The escape command. {arg FORM} is an arbitrary Lisp expression that is evaluated within the context established by the {lisp PRINTOUT} form, i.e., {arg FORM} can assume that the primary output file has been set to be the {arg FILE} argument to {lisp PRINTOUT}. Note that nothing is done with the {it value} of {arg FORM}; any printing desired is accomplished by {arg FORM} itself, and the value is discarded. } {End LabeledList Escaping to LISP} Note: Although {lisp PRINTOUT} logically encloses its translation in a {fn RESETFORM} ({PageRef Fn RESETFORM}) to change the primary output file to the {arg FILE} argument (if non-{lisp NIL}), in most cases it can actually pass {arg FILE} (or a locally bound variable if {arg FILE} is a non-trivial expression) to each printing function. Thus, the {fn RESETFORM} is only generated when the {lisp #} command is used, or user-defined commands (below) are used. If many such occur in repeated {lisp PRINTOUT} forms, it may be more efficient to embed them all in a single {fn RESETFORM} which changes the primary output file, and then specify {arg FILE}={lisp NIL} in the {lisp PRINTOUT} expressions themselves. }{End SubSec Escaping to LISP} {Begin SubSec User-Defined Commands} {Title User-Defined Commands} {Text The collection of commands and options outlined above is aimed at fulfilling all common printing needs. However, certain applications might have other, more specialized printing idioms, so a facility is provided whereby the user can define new commands. This is done by adding entries to the global list {index PRINTOUTMACROS VAR}{var PRINTOUTMACROS} to define how the new commands are to be translated. {vardef {name PRINTOUTMACROS} {text {var PRINTOUTMACROS} is an association-list whose elements are of the form {lisp ({arg COMM} {arg FN})}. Whenever {arg COMM} appears in command position in the sequence of {lisp PRINTOUT} commands (as opposed to an argument position of another command), {arg FN} is applied to the tail of the command-list (including the command). {note can FN be a lambda expr?? Sure--bvm} After inspecting as much of the tail as necessary, the function must return a list whose {fn CAR} is the translation of the user-defined command and its arguments, and whose {fn CDR} is the list of commands still remaining to be translated in the normal way. }} For example, suppose the user wanted to define a command "{lisp ?}", which will cause its single argument to be printed with {fn PRIN1} only if it is not {lisp NIL}. This can be done by entering {lisp (? ?TRAN)} on {var PRINTOUTMACROS}, and defining the function {lisp ?TRAN} as follows: {lispcode (LAMBDA (COMS) (CONS (SUBST (CADR COMS) 'ARG '(PROG ((TEMP ARG)) (COND (TEMP (PRIN1 TEMP))))) (CDDR COMS)))} Note that {lisp ?TRAN} does not do any printing itself; it returns a form which, when evaluated in the proper context, will perform the desired action. This form should direct all printing to the primary output file. }{End SubSec User-Defined Commands} {Begin SubSec Special Printing Functions} {Title Special Printing Functions} {Text The paragraph printing commands are translated into calls on the function {fn PRINTPARA}, which may also be called directly: {FnDef {FnName PRINTPARA} {FnArgs LMARG RMARG LIST P2FLAG PARENFLAG FILE} {Text Prints {arg LIST} on {arg FILE} in line-filled paragraph format with its first element beginning at the current line position and ending at or before {arg RMARG}, and with subsequent lines appearing between {arg LMARG} and {arg RMARG}. If {arg P2FLAG} is non-{lisp NIL}, prints elements using {fn PRIN2}, otherwise {fn PRIN1}. If {arg PARENFLAG} is non-{lisp NIL}, then parentheses will be printed around the elements of {arg LIST}. If {arg LMARG} is zero or positive, it is interpreted as an absolute column position. If it is negative, then the left margin will be at {lisp |{arg LMARG}|}+{lisp (POSITION)}. If {arg LMARG}={lisp NIL}, the left margin will be at {lisp (POSITION)}, and the paragraph will appear in block format. If {arg RMARG} is positive, it also is an absolute column position (which may be greater than the current {lisp (LINELENGTH)}). Otherwise, it is interpreted as relative to {lisp (LINELENGTH)}, i.e., the right margin will be at {lisp (LINELENGTH)}+{lisp |{arg RMARG}|}. Example: {lisp (TAB 10) (PRINTPARA 5 -5 LST T)} will {fn PRIN2} the elements of {lisp LST} in a paragraph with the first line beginning at column 10, subsequent lines beginning at column 5, and all lines ending at or before {lisp (LINELENGTH)}-5. The current {lisp (LINELENGTH)} is unaffected by {fn PRINTPARA}, and upon completion, {arg FILE} will be positioned immediately after the last character of the last item of {arg LIST}. {fn PRINTPARA} is a no-op if {arg LIST} is not a list. }} The right-flushing and centering commands translate as calls to the function {fn FLUSHRIGHT}: {FnDef {FnName FLUSHRIGHT} {FnArgs POS X MIN P2FLAG CENTERFLAG FILE} {Text If {arg CENTERFLAG}={lisp NIL}, prints {arg X} right-flushed against position {arg POS} on {arg FILE}; otherwise, centers {arg X} between the current line position and {arg POS}. Makes sure that it spaces over at least {arg MIN} spaces before printing by doing a {fn TERPRI} if necessary; {arg MIN}={lisp NIL} is equivalent to {arg MIN}=1. A positive {arg POS} indicates an absolute position, while a negative {arg POS} signifies the position which is {lisp |{arg POS}|} to the right of the current line position. {arg POS}=0 is interpreted as {lisp (LINELENGTH)}, the right margin. }} }{End SubSec Special Printing Functions} }{End SubSec PRINTOUT}