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 10Usage="$0 [-h] [-n lines/page] page-ranges [file ...]" 11 12usage() 13{ 14 echo "$Usage" 1>&2 15} 16 17phelp() 18{ 19echo "$0: print selected pages. 20Usage: $Usage 21 22If no file names are given, the standard input is read. 23 24The input is grouped into pages and a selected subset of them is printed. 25Formfeeds are acted on correctly. 26 27If the output device does automatic line wrap, lines that longer than 28the width of the output device will result in incorrect output. 29The first non-option argument is a list of pages to print. 30 31Pages are given as a list of ranges separated by commas. 32A range is either one number, two numbers separted by a dash, 33or one number followed by a dash. A range consisting of one 34number followed by a dash extends to the end of the document. 35 36Options: 37-n sets the number of lines per page to n. The default is 66." 38} 39 40while getopts "n:h" opt; do 41 case "$opt" in 42 n) LinesPerPage=$OPTARG;; 43 h) phelp; exit 0;; 44 *) usage; exit 2;; 45 esac 46done 47 48shift $(($OPTIND - 1)) 49 50if [ $# -eq 0 ]; then 51 echo $0: no page ranges given. 1>&2 52 usage 53 exit 1 54fi 55 56PageList=$1 57shift 58 59gawk " 60BEGIN { 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 117function 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 128function In(a,Min,Max) { 129 return (Min <= a && a <= Max) 130} 131 132function 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). 145function 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 153function 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' "$@" 188