]> git.ipfire.org Git - thirdparty/bash.git/blob - examples/scripts.v2/pages
Bash-4.2 patch 45
[thirdparty/bash.git] / examples / scripts.v2 / pages
1 #! /bin/bash
2 #
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
7 #
8 # conversion to bash v2 syntax by Chet Ramey
9
10 Usage="$0 [-h] [-n lines/page] page-ranges [file ...]"
11
12 usage()
13 {
14 echo "$Usage" 1>&2
15 }
16
17 phelp()
18 {
19 echo "$0: print selected pages.
20 Usage: $Usage
21
22 If no file names are given, the standard input is read.
23
24 The input is grouped into pages and a selected subset of them is printed.
25 Formfeeds are acted on correctly.
26
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.
30
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.
35
36 Options:
37 -n sets the number of lines per page to n. The default is 66."
38 }
39
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
47
48 shift $(($OPTIND - 1))
49
50 if [ $# -eq 0 ]; then
51 echo $0: no page ranges given. 1>&2
52 usage
53 exit 1
54 fi
55
56 PageList=$1
57 shift
58
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
83 }
84
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]])
92 }
93
94 RangeNum = LineNum = PageNum = 1
95 InRange = In(PageNum,RangeStarts[RangeNum],RangeEnds[RangeNum])
96 FS = "\014"
97 }
98
99 {
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
111 }
112 if (InRange)
113 print ""
114 LineNum++
115 }
116
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
126 }
127
128 function In(a,Min,Max) {
129 return (Min <= a && a <= Max)
130 }
131
132 function ErrExit(S) {
133 print S > "/dev/stderr"
134 Err = 1
135 exit 1
136 }
137
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
151 }
152
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
159 }
160 return
161 }
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
175 }
176 }
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)
186 }
187 ' "$@"