| 1 | #! /bin/bash
|
|---|
| 2 | #
|
|---|
| 3 | # original from:
|
|---|
| 4 | # @(#) pages.sh 1.0 92/09/26
|
|---|
| 5 | # 92/09/05 John H. DuBois III ([email protected])
|
|---|
| 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
|
|---|
|
|---|