home *** CD-ROM | disk | FTP | other *** search
- :
- # @(#) pages.sh 1.0 96/06/18
- # 92/09/05 John H. DuBois III (jhdiii@armory.com)
- # 92/09/26 Added help
- # 95/05/01 Use ranges lib
- # 96/06/18 Ported to 3.2v5 awk
-
- Usage="$0 [-h] [-lines/page] page-ranges [file ...]"
-
- case "$1" in
- -[0-9]*) LinesPerPage=$1; shift;;
- -h) echo \
- "$0: print selected pages.
- Usage: $Usage
-
- If no file names are given, the standard input is read.
-
- The input is grouped into pages and a selected subset of them is printed.
- Formfeeds are acted on correctly.
-
- If the output device does automatic line wrap, lines that longer than
- the width of the output device will result in incorrect output.
- The first non-option argument is a list of pages to print.
-
- Pages are given as a list of ranges separated by commas.
- A range is either one number, two numbers separted by a dash,
- or one number followed by a dash. A range consisting of one
- number followed by a dash extends to the end of the document.
-
- Options:
- -n sets the number of lines per page to n. The default is 66."
- exit 0;;
- esac
-
- if [ $# = 0 ]; then
- echo \
- "No ranges given. Usage: $Usage" 1>&2
- exit 1
- fi
-
- PageList=$1
- shift
-
- /usr/bin/awk "
- BEGIN {
- PageList = \"$PageList\"; LinesPerPage = substr(\"$LinesPerPage\""',2)
- if (LinesPerPage == "")
- LinesPerPage = 66
- else
- if (LinesPerPage !~ "[1-9][0-9]*")
- ErrExit("Bad value for lines per page: " LinesPerPage)
- LinesPerPage += 0 # Force to be a number so it will be compared that way
- if ((Err = MakeRangeSet(PageList,Ranges)) != "")
- ErrExit(Err)
- NumRanges = Ranges["n"]
-
- RangeNum = LineNum = PageNum = 1
- InRange = In(PageNum,Ranges["s",RangeNum],Ranges["e",RangeNum])
- FS = "\014"
- }
-
- # Ranges is a list of positive integer ranges in the form m-n,o-p,q,r-s...
- function MakeRangeSet(RangeSet,Ranges,
- RangeStrings,NumRanges,i,StartRange,EndRange,TmpRangeStarts,TmpRangeEnds,k) {
- NumRanges = split(PageList,RangeStrings,",")
- for (i = 1; i <= NumRanges; i++) {
- if ((StartRange = EndRange = RangeStrings[i]) !~ \
- "^[0-9]+(-([0-9]+)?)?$")
- return "Bad range \"" StartRange "\""
- sub("-.*","",StartRange)
- sub(".*-","",EndRange)
- # StartRange is now the starting value (if any) and
- # EndRange is the ending value (if any).
- if (EndRange == "")
- EndRange = 2 ^ 30
- if (StartRange == "")
- StartRange = 1
- # Force StartRange and EndRange to be numeric values
- if ((StartRange !~ /^[1-9][0-9]*$/) || (EndRange !~ /^[1-9][0-9]*$/))
- return "Invalid number in range " RangeStrings[i]
- if (StartRange > EndRange)
- return "Range start comes after range end in " RangeStrings[i]
- # Store the rang for later sorting
- TmpRangeStarts[i] = StartRange
- TmpRangeEnds[i] = EndRange
- }
-
- # Sort ranges
- qsort(TmpRangeStarts,k)
- Ranges["e",0] = 0
-
- # Save ranges in sorted order, and check for overlapping ranges.
- for (i = 1; i <= NumRanges; i++) {
- Ranges["e",i] = TmpRangeEnds[k[i]]
- if ((Ranges["s",i] = TmpRangeStarts[k[i]]) <= Ranges["e",i - 1])
- return \
- "Overlapping ranges: " RangeStrings[k[i]] "," RangeStrings[k[i - 1]]
- }
- Ranges["n"] = NumRanges
- return ""
- }
-
- {
- if (LineNum > LinesPerPage)
- NewPage()
- if (InRange)
- printf "%s",$1
- # Deal with formfeeds
- for (i = 2; i <= NF; i++) {
- if (InRange)
- printf "\014"
- NewPage()
- if (InRange)
- printf "%s",$i
- }
- if (InRange)
- print ""
- LineNum++
- }
-
- function NewPage() {
- PageNum++
- LineNum = 1
- # At the start of each page, check whether we are in a print range
- WereInRange = InRange
- InRange = In(PageNum,Ranges["s",RangeNum],Ranges["e",RangeNum])
- # If last page was in range and we no longer are, move to next range
- if (WereInRange && !InRange && ++RangeNum > NumRanges)
- exit
- }
-
- function In(a,Min,Max) {
- return (Min <= a && a <= Max)
- }
-
- function ErrExit(S) {
- print S > "/dev/stderr"
- Err = 1
- exit 1
- }
-
- # Arr is an array of values with arbitrary indices.
- # Array k is returned with numeric indices 1..n.
- # The values in k are the indices of array arr,
- # ordered so that if array arr is stepped through
- # in the order arr[k[1]] .. arr[k[n]], it will be stepped
- # through in order of the values of its elements.
- # The return value is the number of elements in the array (n).
- function qsort(arr,k, ArrInd,end) {
- end = 0
- for (ArrInd in arr)
- k[++end] = ArrInd;
- qsortseg(arr,k,1,end);
- return end
- }
-
- function qsortseg(arr,k,start,end, left,right,sepval,tmp,tmpe,tmps) {
- # handle two-element case explicitly for a tiny speedup
- if ((end - start) == 1) {
- if (arr[tmps = k[start]] > arr[tmpe = k[end]]) {
- k[start] = tmpe
- k[end] = tmps
- }
- return
- }
- left = start;
- right = end;
- sepval = arr[k[int((left + right) / 2)]]
- # Make every element <= sepval be to the left of every element > sepval
- while (left < right) {
- while (arr[k[left]] < sepval)
- left++
- while (arr[k[right]] > sepval)
- right--
- if (left < right) {
- tmp = k[left]
- k[left++] = k[right]
- k[right--] = tmp
- }
- }
- if (left == right)
- if (arr[k[left]] < sepval)
- left++
- else
- right--
- if (start < right)
- qsortseg(arr,k,start,right)
- if (left < end)
- qsortseg(arr,k,left,end)
- }
- ' "$@"
-