Imported from ../bash-2.0.tar.gz.
[platform/upstream/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 ' "$@"