summaryrefslogtreecommitdiff
path: root/dviware/dvi2bitmap/PageRange.cc
diff options
context:
space:
mode:
authorNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
committerNorbert Preining <norbert@preining.info>2019-09-02 13:46:59 +0900
commite0c6872cf40896c7be36b11dcc744620f10adf1d (patch)
tree60335e10d2f4354b0674ec22d7b53f0f8abee672 /dviware/dvi2bitmap/PageRange.cc
Initial commit
Diffstat (limited to 'dviware/dvi2bitmap/PageRange.cc')
-rw-r--r--dviware/dvi2bitmap/PageRange.cc227
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;
+}