diff options
Diffstat (limited to 'dviware/dvi2bitmap/PageRange.cc')
-rw-r--r-- | dviware/dvi2bitmap/PageRange.cc | 227 |
1 files changed, 227 insertions, 0 deletions
diff --git a/dviware/dvi2bitmap/PageRange.cc b/dviware/dvi2bitmap/PageRange.cc new file mode 100644 index 0000000000..12d8f9b985 --- /dev/null +++ b/dviware/dvi2bitmap/PageRange.cc @@ -0,0 +1,227 @@ +/* This file is part of dvi2bitmap; see README for copyrights and licence */ + +#include <config.h> + +#include "PageRange.h" +#include <iostream> + +#ifdef HAVE_CSTD_INCLUDE +#include <cstdlib> +#include <cctype> +#else +#include <stdlib.h> +#include <ctype.h> +#endif + +verbosities PageRange::verbosity_ = normal; + +/** + * Constructs a new PageRange object. This represents a selection of + * selected pages. When created, the <code>PageRange</code> object + * represents all pages, but this set can be constrained in a variety + * of ways using the {@link #addSpec} method. The resulting object + * can be queried, to ask whether a particular page would be included + * in the set, using the {@link #isSelected} method. + */ +PageRange::PageRange() + : useCounts_(true), useCountNo_(0), + first_(0), last_(0), rangeType_(unset) +{ +} + +/** + * Add a constraint to the set of selected pages represented by this + * PageRange object. The arguments are a selector, which is one of + * the characters `l', `p', or `P', and a string representing one or + * more numbers. The meanings of the three selectors are as follows. + * + * <dl> + * <dt>'l' pagenum</dt> + * <dd>The last page printed will be the first one num- + * bered num Default is the last page in the document. + * If the num is prefixed by an equals sign, then it + * (and any argument to the -p option) is treated as a + * sequence number, rather than a value to compare + * with <code>\\count0</code> values. Thus, using -l =9 will end + * with the ninth page of the document, no matter what + * the pages are actually numbered.</dd> + * + * <dt>'p' pagenum</dt> + * <dd>The first page printed will be the first one num- + * bered num. Default is the first page in the docu- + * ment. If the num is prefixed by an equals sign, + * then it (and any argument to the -l option) is + * treated as a sequence number, rather than a value + * to compare with <code>\\count0</code> values. Thus, using -p =3 + * will start with the third page of the document, no + * matter what the pages are actually numbered.</dd> + * + * <dt>'P' pagelist</dt> + * <dd>A comma-separated list of pages and ranges (a-b) + * may be given, which will be interpreted as <code>\\count0</code> + * values. Pages not specified will not be printed. + * Multiple -pp options may be specified or all pages + * and page ranges can be specified with one -pp + * option.</dd> + * </dl> + * + * <p>Any of these specifications may be prefixed by either + * <code>=</code> or <code>:n:</code> + * In the former case, DVI page numbers are used rather than TeX + * <code>\\count</code> registers; in the latter case, the program examines the + * <code>\\countn</code> register rather than the default <code>\\count0</code> + * + * <p>Thus, the syntax of pagelist is extended to satisfy: + * <pre> + * pagenum: prefix* number + * pagelist: prefix* page-or-range [',' page-or-range]* + * prefix: '=' | ':' number ':' + * page-or-range: number | number-number + * </pre> + * + * @param type one of the letters `l', `p', `P'. + * @param spec a page specification conforming to the grammar above + */ +bool PageRange::addSpec (const char type, const char *spec) +{ + bool parseOK = true; + + // prefix* + for (bool readPrefix = true; readPrefix; ) + switch (*spec) + { + case '=': + useCounts_ = false; + spec++; + break; + case ':': + { + spec++; + char *endp; + int countnum = static_cast<int>(STD::strtol (spec, &endp, 10)); + spec = endp; + if (*spec != ':') + { + parseOK = false; + readPrefix = false; + } + else + { + if (countnum < 0 || countnum > 9) parseOK = false; + useCountNo_ = countnum; + spec++; + } + break; + } + default: + readPrefix = false; + } + // now have spec pointing at first page-or-range or pagenum + + switch (type) + { + case 'p': + if (rangeType_ == ranges) + { + if (verbosity_ >= normal) + std::cerr << "Inconsistent range specs\n"; + parseOK = false; + } + else + { + first_ = STD::atoi (spec); + rangeType_ = oneRange; + } + break; + + case 'P': + { + if (rangeType_ == oneRange) + parseOK = false; + else + rangeType_ = ranges; + + char *endp; + int p1=0, p2; + endp = const_cast<char*>(spec); + char lastsep = ','; + while (*endp != '\0' && parseOK) + { + p2 = static_cast<int>(STD::strtol (spec, &endp, 10)); + if (endp == spec) // no digits found + { + parseOK = false; + continue; + } + + switch (lastsep) + { + case ',': // single page or start of range + setPages_[p2] = true; + p1 = p2; + break; + case '-': // end of range + if (p1 > p2) + parseOK = false; + else + for (int i=p1; i<=p2; i++) + setPages_[i] = true; + break; + default: + parseOK = false; + break; + } + lastsep = *endp; + spec = endp+1; + // now have endp pointing at a separator or \0, + // spec at next char + } + } + break; + + case 'l': + if (rangeType_ == ranges) + { + if (verbosity_ >= normal) + std::cerr << "Inconsistent range specs\n"; + parseOK = false; + } + else + { + last_ = STD::atoi (spec); + rangeType_ = oneRange; + } + break; + + default: + parseOK = false; + } + + return parseOK; +} + +/** + * Returns true if the specified page is to be included. We test + * either the page-sequence number or the TeX <code>\\count0-9</code> + * registers, depending on how the page range was specified. + * + * @param pagenum a page-sequence number, counting pages from the + * beginning of the DVI file + * @param count is the array of TeX <code>\\count0-9</code> register + * @return true if the current settings of this PageRange object + * would indicate that the specified page is to be printed + */ +bool PageRange::isSelected (const int pagenum, const int* count) +{ + bool rval; + if (rangeType_ == unset) + return true; + + int testval = (useCounts_ ? count[useCountNo_] : pagenum); + if (rangeType_ == oneRange) + rval = testval >= first_ && (last_ == 0 || testval <= last_); + else + rval = setPages_[testval]; + + return rval; +} |