+ /* --- Use fast algorithm for binary radix --- *
+ *
+ * This is the restart point after having parsed a radix number from the
+ * input. We check whether the radix is binary, and if so use a fast
+ * algorithm which just stacks the bits up in the right order.
+ */
+
+restart:
+ switch (rd) {
+ unsigned bit;
+
+ case 2: bit = 1; goto bin;
+ case 4: bit = 2; goto bin;
+ case 8: bit = 3; goto bin;
+ case 16: bit = 4; goto bin;
+ case 32: bit = 5; goto bin;
+ case 64: bit = 6; goto bin;
+ case 128: bit = 7; goto bin;
+ default:
+ break;
+
+ /* --- The fast binary algorithm --- *
+ *
+ * We stack bits up starting at the top end of a word. When one word is
+ * full, we write it to the integer, and start another with the left-over
+ * bits. When the array in the integer is full, we resize using low-level
+ * calls and copy the current data to the top end. Finally, we do a single
+ * bit-shift when we know where the end of the number is.
+ */
+
+ bin: {
+ mpw a = 0;
+ unsigned b = MPW_BITS;
+ size_t len, n;
+ mpw *v;
+
+ m = mp_dest(MP_NEW, 1, nf);
+ len = n = m->sz;
+ n = len;
+ v = m->v + n;
+ for (;; ch = ops->get(p)) {
+ unsigned x;
+
+ if (ch < 0)
+ break;
+
+ /* --- Check that the character is a digit and in range --- */
+
+ if (radix < 0)
+ x = ch % rd;
+ else {
+ if (!isalnum(ch))
+ break;
+ if (ch >= '0' && ch <= '9')
+ x = ch - '0';
+ else {
+ if (rd <= 36)
+ ch = tolower(ch);
+ if (ch >= 'a' && ch <= 'z') /* ASCII dependent! */
+ x = ch - 'a' + 10;
+ else if (ch >= 'A' && ch <= 'Z')
+ x = ch - 'A' + 36;
+ else
+ break;
+ }
+ }
+ if (x >= rd)
+ break;
+
+ /* --- Feed the digit into the accumulator --- */
+
+ f |= f_ok;
+ if (!x && !(f & f_start))
+ continue;
+ f |= f_start;
+ if (b > bit) {
+ b -= bit;
+ a |= MPW(x) << b;
+ } else {
+ a |= MPW(x) >> (bit - b);
+ b += MPW_BITS - bit;
+ *--v = MPW(a);
+ n--;
+ if (!n) {
+ n = len;
+ len <<= 1;
+ v = mpalloc(m->a, len);
+ memcpy(v + n, m->v, MPWS(n));
+ mpfree(m->a, m->v);
+ m->v = v;
+ v = m->v + n;
+ }
+ a = (b < MPW_BITS) ? MPW(x) << b : 0;
+ }
+ }
+
+ /* --- Finish up --- */
+
+ if (!(f & f_ok)) {
+ mp_drop(m);
+ m = 0;
+ } else {
+ *--v = MPW(a);
+ n--;
+ m->sz = len;
+ m->vl = m->v + len;
+ m->f &= ~MP_UNDEF;
+ m = mp_lsr(m, m, (unsigned long)n * MPW_BITS + b);
+ }
+ ops->unget(ch, p);
+ goto done;
+ }}
+