summaryrefslogtreecommitdiff
path: root/ipl/progs/iprint.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/progs/iprint.icn')
-rw-r--r--ipl/progs/iprint.icn258
1 files changed, 258 insertions, 0 deletions
diff --git a/ipl/progs/iprint.icn b/ipl/progs/iprint.icn
new file mode 100644
index 0000000..2bddc84
--- /dev/null
+++ b/ipl/progs/iprint.icn
@@ -0,0 +1,258 @@
+############################################################################
+#
+# File: iprint.icn
+#
+# Subject: Program to print Icon program
+#
+# Author: Robert J. Alexander
+#
+# Date: March 26, 2002
+#
+############################################################################
+#
+# This file is in the public domain.
+#
+############################################################################
+#
+# The defaults are set up for printing of Icon programs, but
+# through command line options it can be set up to print programs
+# in other languages, too (such as C). This program has several
+# features:
+#
+# If a program is written in a consistent style, this program
+# will attempt to keep whole procedures on the same page. The
+# default is to identify the end of a print group (i.e. a pro-
+# cedure) by looking for the string "end" at the beginning of a
+# line. Through the -g option, alternative strings can be used to
+# signal end of a group. Using "end" as the group delimiter
+# (inclusive), comments and declarations prior to the procedure are
+# grouped with the procedure. Specifying a null group delimiter
+# string (-g '') suppresses grouping.
+#
+# Page creases are skipped over, and form-feeds (^L) embedded in
+# the file are handled properly. (Form-feeds are treated as spaces
+# by many C compilers, and signal page ejects in a listing). Page
+# headings (file name, date, time, page number) are normally
+# printed unless suppressed by the -h option.
+#
+# Options:
+#
+# -n number lines.
+#
+# -pN page length: number of lines per page (default: 60
+# lines).
+#
+# -tN tab stop spacing (default: 8).
+#
+# -h suppress page headings.
+#
+# -l add three lines at top of each page for laser printer.
+#
+# -gS end of group string (default: "end").
+#
+# -cS start of comment string (default: "#").
+#
+# -xS end of comment string (default: none).
+#
+# -i ignore FF at start of line.
+#
+# Any number of file names specified will be printed, each
+# starting on a new page.
+#
+# For example, to print C source files such as the Icon source
+# code, use the following options:
+#
+# iprint -g ' }' -c '/*' -x '*/' file ...
+#
+# Control lines:
+#
+# Control lines are special character strings that occur at the
+# beginnings of lines that signal special action. Control lines
+# begin with the start of comment string (see options). The control
+# lines currently recognized are:
+#
+# <comment string>eject -- page eject (line containing "eject"
+# does not print).
+#
+# <comment string>title -- define a title line to print at top
+# of each page. Title text is separated from the <comment
+# string>title control string by one space and is terminated by
+# <end of comment string> or end of line, whichever comes first.
+#
+# <comment string>subtitle -- define a sub-title line to print
+# at top of each page. Format is parallel to the "title" control
+# line, above.
+#
+# If a page eject is forced by maximum lines per page being
+# exceeded (rather than intentional eject via control line, ff, or
+# grouping), printing of blank lines at the top of the new page is
+# suppressed. Line numbers will still be printed correctly.
+#
+############################################################################
+
+global pagelines,tabsize,lines,page,datetime,title,subtitle,pagestatus,blanks,
+ group,numbers,noheaders,hstuff,gpat,comment,comment_end,laser,
+ ignore_ff
+
+procedure main(arg)
+ local files,x
+ &dateline ? {tab(find(",")) ; move(2) ; datetime := tab(0)}
+ files := []
+ pagelines := 60
+ tabsize := 8
+ gpat := "end"
+ comment := "#"
+
+ while x := get(arg) do {
+ if match("-",x) then { # Arg is an option
+ case x[2] of {
+ "n": numbers := "yes"
+ "p": {
+ pagelines := ("" ~== x[3:0]) | get(arg)
+ if not (pagelines := integer(pagelines)) then
+ stop("Invalid -p parameter: ",pagelines)
+ }
+ "t": {
+ tabsize := ("" ~== x[3:0]) | get(arg)
+ if not (tabsize := integer(tabsize)) then
+ stop("Invalid -t parameter: ",tabsize)
+ }
+ "h": noheaders := "yes"
+ "l": laser := "yes"
+ "g": {
+ gpat := ("" ~== x[3:0]) | get(arg)
+ }
+ "c": {
+ comment := ("" ~== x[3:0]) | get(arg)
+ }
+ "x": {
+ comment_end := ("" ~== x[3:0]) | get(arg)
+ }
+ "i": ignore_ff := "yes"
+ default: stop("Invalid option ",x)
+ }
+ }
+ else put(files,x)
+ }
+ if *files = 0 then stop("usage: iprint -options file ...\n_
+ options:\n_
+ \t-n\tnumber the lines\n_
+ \t-p N\tspecify lines per page (default 60)\n_
+ \t-t N\tspecify tab width (default 8)\n_
+ \t-h\tsuppress page headers\n_
+ \t-l\tadd 3 blank lines at top of each page\n_
+ \t-g S\tpattern for last line in group\n_
+ \t-c S\t'start of comment' string\n_
+ \t-x S\t'end of comment' string\n_
+ \t-i\tignore FF")
+ every x := !files do expand(x)
+end
+
+procedure expand(fn)
+ local f,line,cmd,linenbr,fname
+ f := open(fn) | stop("Can't open ",fn)
+ fn ? {
+ while tab(find("/")) & move(1)
+ fname := tab(0)
+ }
+ hstuff := fname || " " || datetime || " page "
+ title := subtitle := &null
+ lines := pagelines
+ page := 0 ; linenbr := 0
+ group := []
+ while line := trim(read(f)) do {
+ if \ignore_ff then while match("\f",line) do line[1] := ""
+ linenbr +:= 1
+ if match("\f",line) then {
+ dumpgroup()
+ lines := pagelines
+ repeat {
+ line[1] := ""
+ if not match("\f",line) then break
+ }
+ }
+ line ? {
+ if =comment & cmd := =("eject" | "title" | "subtitle") then {
+ dumpgroup()
+ case cmd of { # Command line
+ "title": (move(1) & title := trim(tab(find(comment_end)))) |
+ (title := &null)
+ "subtitle": (move(1) & subtitle := trim(tab(find(comment_end)))) |
+ (subtitle := &null)
+ }
+ lines := pagelines
+ }
+ else { # Ordinary (non-command) line
+ if not (*group = 0 & *line = 0) then {
+ put(group,line)
+ if \numbers then put(group,linenbr)
+ }
+ if endgroup(line) then dumpgroup()
+ }
+ }
+ }
+ dumpgroup()
+ close(f)
+ lines := pagelines
+end
+
+procedure dumpgroup()
+ local line,linenbr
+ if *group > 0 then {
+ if lines + *group / ((\numbers & 2) | 1) + 2 >= pagelines then
+ lines := pagelines
+ else {write("\n") ; lines +:= 2}
+ while line := get(group) do {
+ if \numbers then linenbr := get(group)
+ if lines >= pagelines then {
+ printhead()
+ }
+ if *line = 0 then {
+ if pagestatus ~== "empty" then {blanks +:= 1 ; lines +:= 1}
+ next
+ }
+ every 1 to blanks do write()
+ blanks := 0
+ pagestatus := "not empty"
+ if \numbers then writes(right(linenbr,5)," ")
+ write(detab(line))
+ lines +:= 1
+ }
+ }
+ return
+end
+
+procedure endgroup(s)
+ return match("" ~== gpat,s)
+end
+
+procedure printhead()
+ static ff,pg
+ writes(ff) ; ff := "\f"
+ lines := 0
+ pg := string(page +:= 1)
+ if /noheaders then {
+ if \laser then write("\n\n")
+ write(left(\title | "",79 - *hstuff - *pg),hstuff,pg)
+ lines +:= 2
+ write(\subtitle) & lines +:= 1
+ write()
+ }
+ pagestatus := "empty"
+ blanks := 0
+ return
+end
+
+procedure detab(s)
+ local t
+ t := ""
+ s ? {
+ while t ||:= tab(find("\t")) do {
+ t ||:= repl(" ",tabsize - *t % tabsize)
+ move(1)
+ }
+ t ||:= tab(0)
+ }
+ return t
+end
+