mirror of
https://github.com/qpdf/qpdf.git
synced 2024-12-22 10:58:58 +00:00
Support "r" in page ranges (fixes #155)
This commit is contained in:
parent
e577dfc87e
commit
666f794393
@ -1,3 +1,10 @@
|
||||
2018-03-04 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
* On the command line when specifying page ranges, support
|
||||
preceding a page number by "r" to indicate that it should be
|
||||
counted from the end. For example, the range r3-r1 would indicate
|
||||
the last three pages of a document.
|
||||
|
||||
2018-03-03 Jay Berkenbilt <ejb@ql.org>
|
||||
|
||||
* Ignore zlib data check errors while uncompressing streams. This
|
||||
|
@ -818,13 +818,15 @@ make
|
||||
</para>
|
||||
<para>
|
||||
The page range is a set of numbers separated by commas, ranges of
|
||||
numbers separated dashes, or combinations of those. The character
|
||||
“z” represents the last page. Pages can appear in any
|
||||
order. Ranges can appear with a high number followed by a low
|
||||
number, which causes the pages to appear in reverse. Repeating a
|
||||
number will cause an error, but you can use the workaround
|
||||
discussed above should you really want to include the same page
|
||||
twice.
|
||||
numbers separated dashes, or combinations of those. The character
|
||||
“z” represents the last page. A number preceded by an
|
||||
“r” indicates to count from the end, so
|
||||
“r3-r1” would be the last three pages of the document.
|
||||
Pages can appear in any order. Ranges can appear with a high
|
||||
number followed by a low number, which causes the pages to appear
|
||||
in reverse. Repeating a number will cause an error, but you can
|
||||
use the workaround discussed above should you really want to
|
||||
include the same page twice.
|
||||
</para>
|
||||
<para>
|
||||
Example page ranges:
|
||||
@ -840,6 +842,17 @@ make
|
||||
<literal>z-1</literal>: all pages in the document in reverse
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>r3-r1</literal>: the last three pages of the document
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
<literal>r1-r3</literal>: the last three pages of the document
|
||||
in reverse order
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
<para>
|
||||
|
40
qpdf/qpdf.cc
40
qpdf/qpdf.cc
@ -358,11 +358,12 @@ input.\n\
|
||||
\n\
|
||||
The page range is a set of numbers separated by commas, ranges of\n\
|
||||
numbers separated dashes, or combinations of those. The character\n\
|
||||
\"z\" represents the last page. Pages can appear in any order. Ranges\n\
|
||||
can appear with a high number followed by a low number, which causes the\n\
|
||||
pages to appear in reverse. Repeating a number will cause an error, but\n\
|
||||
the manual discusses a workaround should you really want to include the\n\
|
||||
same page twice.\n\
|
||||
\"z\" represents the last page. A number preceded by an \"r\" indicates\n\
|
||||
to count from the end, so \"r3-r1\" would be the last three pages of the\n\
|
||||
document. Pages can appear in any order. Ranges can appear with a\n\
|
||||
high number followed by a low number, which causes the pages to appear in\n\
|
||||
reverse. Repeating a number will cause an error, but the manual discusses\n\
|
||||
a workaround should you really want to include the same page twice.\n\
|
||||
\n\
|
||||
If the page range is omitted, the range of 1-z is assumed. qpdf decides\n\
|
||||
that the page range is omitted if the range argument is either -- or a\n\
|
||||
@ -577,6 +578,22 @@ static void show_encryption(QPDF& pdf, Options& o)
|
||||
}
|
||||
}
|
||||
|
||||
static int maybe_from_end(int num, bool from_end, int max)
|
||||
{
|
||||
if (from_end)
|
||||
{
|
||||
if (num > max)
|
||||
{
|
||||
num = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
num = max + 1 - num;
|
||||
}
|
||||
}
|
||||
return num;
|
||||
}
|
||||
|
||||
static std::vector<int> parse_numrange(char const* range, int max,
|
||||
bool throw_error = false)
|
||||
{
|
||||
@ -593,6 +610,7 @@ static std::vector<int> parse_numrange(char const* range, int max,
|
||||
st_after_number } state = st_top;
|
||||
bool last_separator_was_dash = false;
|
||||
int cur_number = 0;
|
||||
bool from_end = false;
|
||||
while (*p)
|
||||
{
|
||||
char ch = *p;
|
||||
@ -616,14 +634,25 @@ static std::vector<int> parse_numrange(char const* range, int max,
|
||||
state = st_after_number;
|
||||
cur_number = max;
|
||||
}
|
||||
else if (ch == 'r')
|
||||
{
|
||||
if (! (state == st_top))
|
||||
{
|
||||
throw std::runtime_error("r not expected");
|
||||
}
|
||||
state = st_in_number;
|
||||
from_end = true;
|
||||
}
|
||||
else if ((ch == ',') || (ch == '-'))
|
||||
{
|
||||
if (! ((state == st_in_number) || (state == st_after_number)))
|
||||
{
|
||||
throw std::runtime_error("unexpected separator");
|
||||
}
|
||||
cur_number = maybe_from_end(cur_number, from_end, max);
|
||||
work.push_back(cur_number);
|
||||
cur_number = 0;
|
||||
from_end = false;
|
||||
if (ch == ',')
|
||||
{
|
||||
state = st_top;
|
||||
@ -649,6 +678,7 @@ static std::vector<int> parse_numrange(char const* range, int max,
|
||||
}
|
||||
if ((state == st_in_number) || (state == st_after_number))
|
||||
{
|
||||
cur_number = maybe_from_end(cur_number, from_end, max);
|
||||
work.push_back(cur_number);
|
||||
}
|
||||
else
|
||||
|
@ -1092,9 +1092,19 @@ my @nrange_tests = (
|
||||
["1-10,1234,5",
|
||||
"qpdf: error in numeric range 1-10,1234,5: number 1234 out of range",
|
||||
2],
|
||||
["1,3,5-10,z-13,13,9,z,2",
|
||||
"numeric range 1,3,5-10,z-13,13,9,z,2" .
|
||||
" -> 1 3 5 6 7 8 9 10 15 14 13 13 9 15 2",
|
||||
["1,r,3",
|
||||
"qpdf: error in numeric range 1,r,3: number 16 out of range",
|
||||
2],
|
||||
["1,r16,3",
|
||||
"qpdf: error in numeric range 1,r16,3: number 0 out of range",
|
||||
2],
|
||||
["1,3,5-10,z-13,13,9,z,2,r2-r4",
|
||||
"numeric range 1,3,5-10,z-13,13,9,z,2,r2-r4" .
|
||||
" -> 1 3 5 6 7 8 9 10 15 14 13 13 9 15 2 14 13 12",
|
||||
0],
|
||||
["r1-r15", # r\d+ at end
|
||||
"numeric range r1-r15" .
|
||||
" -> 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1",
|
||||
0],
|
||||
);
|
||||
$n_tests += scalar(@nrange_tests);
|
||||
|
Loading…
Reference in New Issue
Block a user