Patch-ID: bash41-003
[bash.git] / examples / scripts.v2 / pages
blob66ebc5f96bdf1e6adbe85060e7fcb039fb91b500
1 #! /bin/bash
3 # original from:
4 # @(#) pages.sh 1.0 92/09/26
5 # 92/09/05 John H. DuBois III (jhdiii@armory.com)
6 # 92/09/26 Added help
8 # conversion to bash v2 syntax by Chet Ramey
10 Usage="$0 [-h] [-n lines/page] page-ranges [file ...]"
12 usage()
14 echo "$Usage" 1>&2
17 phelp()
19 echo "$0: print selected pages.
20 Usage: $Usage
22 If no file names are given, the standard input is read.
24 The input is grouped into pages and a selected subset of them is printed.
25 Formfeeds are acted on correctly.
27 If the output device does automatic line wrap, lines that longer than
28 the width of the output device will result in incorrect output.
29 The first non-option argument is a list of pages to print.
31 Pages are given as a list of ranges separated by commas.
32 A range is either one number, two numbers separted by a dash,
33 or one number followed by a dash. A range consisting of one
34 number followed by a dash extends to the end of the document.
36 Options:
37 -n sets the number of lines per page to n. The default is 66."
40 while getopts "n:h" opt; do
41 case "$opt" in
42 n) LinesPerPage=$OPTARG;;
43 h) phelp; exit 0;;
44 *) usage; exit 2;;
45 esac
46 done
48 shift $(($OPTIND - 1))
50 if [ $# -eq 0 ]; then
51 echo $0: no page ranges given. 1>&2
52 usage
53 exit 1
56 PageList=$1
57 shift
59 gawk "
60 BEGIN {
61 PageList = \"$PageList\"; LinesPerPage = \"$LinesPerPage\""'
62 if (LinesPerPage == "")
63 LinesPerPage = 66
64 else
65 if (LinesPerPage !~ "[1-9][0-9]*")
66 ErrExit("Bad value for lines per page: " LinesPerPage)
67 LinesPerPage += 0
68 NumRanges = split(PageList,Ranges,",")
69 for (i = 1; i <= NumRanges; i++) {
70 if ((StartRange = EndRange = Ranges[i]) !~ "^[0-9]+(-([0-9]+)?)?$")
71 ErrExit("Bad range \"" StartRange "\"")
72 sub("-.*","",StartRange)
73 sub(".*-","",EndRange)
74 if (EndRange == "")
75 EndRange = 2 ^ 30
76 # Force StartRange and EndRange to be numeric values
77 if ((StartRange += 0) == 0 || (EndRange += 0) == 0)
78 ErrExit("Invalid page number \"0\" in range " Ranges[i])
79 if (StartRange > EndRange)
80 ErrExit("Start page comes after end page in range " Ranges[i])
81 TmpRangeStarts[i] = StartRange
82 TmpRangeEnds[i] = EndRange
85 # Sort ranges
86 qsort(TmpRangeStarts,k)
87 RangeEnds[0] = 0
88 for (i = 1; i <= NumRanges; i++) {
89 RangeEnds[i] = TmpRangeEnds[k[i]]
90 if ((RangeStarts[i] = TmpRangeStarts[k[i]]) <= RangeEnds[i - 1])
91 ErrExit("Overlapping ranges: " Ranges[k[i]] "," Ranges[k[i - 1]])
94 RangeNum = LineNum = PageNum = 1
95 InRange = In(PageNum,RangeStarts[RangeNum],RangeEnds[RangeNum])
96 FS = "\014"
100 if (LineNum > LinesPerPage)
101 NewPage()
102 if (InRange)
103 printf "%s",$1
104 # Deal with formfeeds
105 for (i = 2; i <= NF; i++) {
106 if (InRange)
107 printf "\014"
108 NewPage()
109 if (InRange)
110 printf "%s",$i
112 if (InRange)
113 print ""
114 LineNum++
117 function NewPage() {
118 PageNum++
119 LineNum = 1
120 # At the start of each page, check whether we are in a print range
121 WereInRange = InRange
122 InRange = In(PageNum,RangeStarts[RangeNum],RangeEnds[RangeNum])
123 # If last page was in range and we no longer are, move to next range
124 if (WereInRange && !InRange && ++RangeNum > NumRanges)
125 exit
128 function In(a,Min,Max) {
129 return (Min <= a && a <= Max)
132 function ErrExit(S) {
133 print S > "/dev/stderr"
134 Err = 1
135 exit 1
138 # Arr is an array of values with arbitrary indices.
139 # Array k is returned with numeric indices 1..n.
140 # The values in k are the indices of array arr,
141 # ordered so that if array arr is stepped through
142 # in the order arr[k[1]] .. arr[k[n]], it will be stepped
143 # through in order of the values of its elements.
144 # The return value is the number of elements in the array (n).
145 function qsort(arr,k, ArrInd,end) {
146 end = 0
147 for (ArrInd in arr)
148 k[++end] = ArrInd;
149 qsortseg(arr,k,1,end);
150 return end
153 function qsortseg(arr,k,start,end, left,right,sepval,tmp,tmpe,tmps) {
154 # handle two-element case explicitely for a tiny speedup
155 if ((end - start) == 1) {
156 if (arr[tmps = k[start]] > arr[tmpe = k[end]]) {
157 k[start] = tmpe
158 k[end] = tmps
160 return
162 left = start;
163 right = end;
164 sepval = arr[k[int((left + right) / 2)]]
165 # Make every element <= sepval be to the left of every element > sepval
166 while (left < right) {
167 while (arr[k[left]] < sepval)
168 left++
169 while (arr[k[right]] > sepval)
170 right--
171 if (left < right) {
172 tmp = k[left]
173 k[left++] = k[right]
174 k[right--] = tmp
177 if (left == right)
178 if (arr[k[left]] < sepval)
179 left++
180 else
181 right--
182 if (start < right)
183 qsortseg(arr,k,start,right)
184 if (left < end)
185 qsortseg(arr,k,left,end)
187 ' "$@"