summaryrefslogtreecommitdiff
path: root/ipl/progs/format.icn
diff options
context:
space:
mode:
Diffstat (limited to 'ipl/progs/format.icn')
-rw-r--r--ipl/progs/format.icn162
1 files changed, 162 insertions, 0 deletions
diff --git a/ipl/progs/format.icn b/ipl/progs/format.icn
new file mode 100644
index 0000000..fc0528d
--- /dev/null
+++ b/ipl/progs/format.icn
@@ -0,0 +1,162 @@
+############################################################################
+#
+# File: format.icn
+#
+# Subject: Program to word wrap a range of text
+#
+# Author: Robert J. Alexander
+#
+# Date: March 26, 2002
+#
+############################################################################
+#
+# This file is in the public domain.
+#
+############################################################################
+#
+# Filter to word wrap a range of text.
+#
+# A number of options are available, including full justification (see
+# usage text, below). All lines that have the same indentation as the
+# first line (or same comment leading character format if -c option)
+# are wrapped. Other lines are left as is.
+#
+# This program is useful in conjunction with editors that can invoke
+# filters on a range of selected text.
+#
+# The -c option attempts to establish the form of a comment based on the
+# first line, then does its best to deal properly with the following
+# lines. The types of comment lines that are handled are those in
+# which each line starts with a "comment" character string (possibly
+# preceded by spaces). While formatting comment lines, text lines
+# following the prototype line that don't match the prototype but are
+# flush with the left margin are also formatted as comments. This
+# feature simplifies initially entering lengthy comments or making
+# major modifications, since new text can be entered without concern
+# for comment formatting, which will be done automatically later.
+#
+############################################################################
+#
+# Links: options
+#
+############################################################################
+
+link options
+
+procedure main(arg)
+ local usage, opts, tabs, comment, format, just1, space, nspace, wchar, Entab
+ local line, pre, empty, outline, spaces, word, len, width, xspace, Detab
+ local outpre
+ #
+ # Process the options.
+ #
+ usage :=
+ "usage: format [-options]\n_
+ \t-w N\tspecify line width (default 72)\n_
+ \t-t N\tspecify tab width (default 8)\n_
+ \t-j\tfully justify lines\n_
+ \t-J\tfully justify last line, too\n_
+ \t-c\tattempt to format program comments\n_
+ \t-n\tdon't put extra spaces after sentences\n_
+ \t-h\tprint help message"
+ opts := options(arg,"ht+w+cjJn")
+ if \opts["h"] then stop(usage)
+ width := integer(\opts["w"]) | 72
+ tabs := (integer(\opts["t"]) | 8) + 1
+ if tabs >= 2 then {
+ Detab := detab
+ Entab := entab
+ }
+ else Entab := Detab := 1
+ comment := opts["c"]
+ format := if \just1 | \opts["j"] then justify else 1
+ just1 := opts["J"]
+ xspace := if \opts["s"] then '' else '.?:!'
+ #
+ # Initialize variables.
+ #
+ space := ' \t'
+ nspace := ~space
+ wchar := nspace
+ #
+ # Read the first line to establish a prototype of comment format
+ # if -c option, or of leading spaces if normal formatting.
+ #
+ line := Detab(read(),tabs) | exit()
+ line ?
+ pre := (tab(many(space)) | "") ||
+ if \comment then
+ tab(many(nspace)) || tab(many(space)) |
+ stop("### Can't establish comment pattern")
+ else
+ ""
+ width -:= *pre
+ empty := trim(pre)
+ outpre := Entab(pre,tabs)
+ outline := spaces := ""
+ repeat {
+ line ? {
+ #
+ # If this line indicates a formatting break...
+ #
+ if (=empty & pos(0)) | (=pre & any(space) | pos(0)) |
+ (/comment & not match(pre)) then {
+ write(outpre,"" ~== outline)
+ outline := spaces := ""
+ write(line)
+ }
+ #
+ # Otherwise continue formatting.
+ #
+ else {
+ =pre
+ tab(0) ? {
+ tab(many(space))
+ while word := tab(many(wchar)) & (tab(many(space)) | "") do {
+ if *outline + *spaces + *word > width then {
+ write(outpre,"" ~== format(outline,width))
+ outline := spaces := ""
+ }
+ outline ||:= spaces || word
+ spaces := if any(xspace,word[-1]) then " " else " "
+ }
+ }
+ }
+ }
+ line := Detab(read(),tabs) | break
+ }
+ write(outpre,"" ~== (if \just1 then justify else 1)(outline,width))
+end
+
+
+#
+# justify(s,width) -- Inserts extra spaces between words of "s" so that
+# "s" will be exactly "width" characters long. "s" is trimmed of
+# spaces on the right and left ends. If "s" contains fewer than two
+# words, or if the trimmed version is longer than "width", the trimmed
+# version of "s" is returned unchanged. Where some gaps between words
+# are required to be wider than others, the extra spaces are
+# distributed randomly to minimize "rivering" in justified paragraphs.
+#
+procedure justify(s,width)
+ local wlist,wset,t,r
+ static space,nspace
+ initial {
+ space := ' '
+ nspace := &cset -- space
+ }
+ s := trim(s[many(space,s) | 1:0])
+ wlist := []
+ s ? while put(wlist,[tab(many(nspace)),*tab(many(space)) | 0])
+ if *s >= width | *wlist < 2 then return s
+ wset := set(wlist[1:-1])
+ t := (width - *s) / *wset
+ every (!wset)[2] +:= t
+ every 1 to (width - *s) % *wset do {
+ (t := ?wset)[2] +:= 1
+ delete(wset,t)
+ }
+ r := ""
+ every t := !wlist do r ||:= t[1] || repl(" ",t[2])
+ return r
+end