aboutsummaryrefslogtreecommitdiffstats
path: root/examples/scripts.v2/pages
blob: 66ebc5f96bdf1e6adbe85060e7fcb039fb91b500 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
#! /bin/bash
#
# original from:
# @(#) pages.sh 1.0 92/09/26
# 92/09/05 John H. DuBois III (jhdiii@armory.com)
# 92/09/26 Added help
#
# conversion to bash v2 syntax by Chet Ramey

Usage="$0 [-h] [-n lines/page] page-ranges [file ...]"

usage()
{
	echo "$Usage" 1>&2
}

phelp()
{
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."
}

while getopts "n:h" opt; do
	case "$opt" in
	n)	LinesPerPage=$OPTARG;;
	h)	phelp; exit 0;;
	*)	usage; exit 2;;
	esac
done

shift $(($OPTIND - 1))

if [ $# -eq 0 ]; then
    echo $0: no page ranges given. 1>&2
    usage
    exit 1
fi

PageList=$1
shift

gawk "
BEGIN {
    PageList = \"$PageList\"; LinesPerPage = \"$LinesPerPage\""'
    if (LinesPerPage == "")
	LinesPerPage = 66
    else
	if (LinesPerPage !~ "[1-9][0-9]*")
	    ErrExit("Bad value for lines per page: " LinesPerPage)
    LinesPerPage += 0
    NumRanges = split(PageList,Ranges,",")
    for (i = 1; i <= NumRanges; i++) {
	if ((StartRange = EndRange = Ranges[i]) !~ "^[0-9]+(-([0-9]+)?)?$")
	    ErrExit("Bad range \"" StartRange "\"")
	sub("-.*","",StartRange)
	sub(".*-","",EndRange)
	if (EndRange == "")
	    EndRange = 2 ^ 30
	# Force StartRange and EndRange to be numeric values
	if ((StartRange += 0) == 0 || (EndRange += 0) == 0)
	    ErrExit("Invalid page number \"0\" in range " Ranges[i])
	if (StartRange > EndRange)
	    ErrExit("Start page comes after end page in range " Ranges[i])
	TmpRangeStarts[i] = StartRange
	TmpRangeEnds[i] = EndRange
    }

    # Sort ranges
    qsort(TmpRangeStarts,k)
    RangeEnds[0] = 0
    for (i = 1; i <= NumRanges; i++) {
	RangeEnds[i] = TmpRangeEnds[k[i]]
	if ((RangeStarts[i] = TmpRangeStarts[k[i]]) <= RangeEnds[i - 1])
	    ErrExit("Overlapping ranges: " Ranges[k[i]] "," Ranges[k[i - 1]])
    }

    RangeNum = LineNum = PageNum = 1
    InRange = In(PageNum,RangeStarts[RangeNum],RangeEnds[RangeNum])
    FS = "\014"
}

{
    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,RangeStarts[RangeNum],RangeEnds[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 explicitely 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)
}
' "$@"