/* * count - program to count. * * Count is a program which counts. It can count up or down by any * interval (in integers); it can print numbers with various * formatting options, in decimal, hexadecimal, or octal. Usage is: * * count [[keyword] value] ... * * where keyword is one of the following * * keyword meaning of value * ------- ---------------- * from number to start counting at * to number to stop counting at * by number to count by (interval) * for count of numbers to generate * range range of numbers to generate * random does not take a value * mod number to reduce modulo * multiples-of number to restrict to multiples of * pad width to pad numbers to (pad with blanks) * 0pad width to pad numbers to (pad with zeros) * zeropad same as 0pad * base base to count in, may be a number or one of * `binary', `octal', `decimal', `hex', or * `hexadecimal'. * prefix a string to print before each number; default * empty. * postfix a string to print after each number; default * "\n". * delay how long to delay between each number and the * next; default no delay. * sync does not take a value * * The value is either a number or a string; only the base, prefix, and * postfix options take arbitrary strings, and the base option accepts * numbers as well. A number can be just a string of digits, in which * case it is interpreted in decimal, or it can be a string beginning * with one of 0b, 0o, 0t, or 0x, which specify (respectively) binary, * octal, decimal, or hex. For compatibility with C, a leading zero * implies octal (like 0o). (The delay argument is an exception; * unlike the other numbers, it is always in decimal and it may be * floating-point.) * * Defaults are applied as follows: * * If no `from' value was given, then: * if `by' or `to' is given and negative then * assume `from' is -1, otherwise +1. * If no `by' value was given, then: * if a `to' value was given and the `to' value is * less than the `from' value, then * assume `by' is -1, otherwise +1. * If no `mod' value was given, don't reduce numbers modulo anything. * If no padding is specified, none is used. * If no prefix is specified, "" is assumed. * If no postfix is specified, "\n" is assumed. * If no base is given, decimal is assumed. * * If no `to' value was given, count will keep printing until it is killed by * something; otherwise it will continue until the next value printed would * be greater or less than the `to' value according as `by' is positive or * negative. If by is 0, count will print the `from' value in an infinite * loop, unless the `to' value is equal to the `from' value (in this case it * prints it only once). * * As its sole author, I explicitly place this code in the public domain. * Anyone may use it in any way for any purpose, though I would appreciate * credit where it is due. * * If you find any bugs I would appreciate hearing, especially if you also * fix them. Write to mouse@rodents.montreal.qc.ca. */ #include #include #include #include #include #include #include #include extern const char *__progname; typedef long long int LLI; typedef unsigned long long int ULLI; static LLI start; static LLI stop; static LLI by; static LLI modulus; static LLI multof; static LLI ncount; static LLI nrange; static int pad; static const char *prefix; static const char *postfix; static const char *basename; static double delay; static int havestart; static int havestop; static int haveby; static int havemodulus; static int havemultof; static int havencount; static int havenrange; static int havepad; static int have0pad; static int havebase; static int haveprefix; static int havepostfix; static int havedelay; static int havesync; static int haverandom; static struct { enum { bigint, integer, string, floating, novalue } kind; void *var; int *have; const char *name; } vars[] = { { bigint, &start, &havestart, "from" }, { bigint, &stop, &havestop, "to" }, { bigint, &by, &haveby, "by" }, { bigint, &modulus, &havemodulus, "mod" }, { bigint, &multof, &havemultof, "multiples-of" }, { bigint, &ncount, &havencount, "for" }, { bigint, &nrange, &havenrange, "range" }, { integer, &pad, &havepad, "pad" }, { integer, &pad, &have0pad, "0pad" }, { integer, &pad, &have0pad, "zeropad" }, { string, &basename, &havebase, "base" }, { string, &prefix, &haveprefix, "prefix" }, { string, &postfix, &havepostfix, "postfix" }, { floating, &delay, &havedelay, "delay" }, { novalue, 0, &havesync, "sync" }, { novalue, 0, &haverandom, "random" } }; #define nvars (sizeof(vars) / sizeof(vars[0])) static struct timeval delaynext; static struct timeval delayinc; static int firstnum; static int base; static struct { const char *name; int base; } bases[] = { { "binary", 2 }, { "octal", 8 }, { "decimal", 10 }, { "hex", 16 }, { "hexadecimal", 16 }, { 0, 0 } }; static int errs; static int interpret_number(const char *str, LLI *ip) { char *sp; int base; LLI val; int neg; base = 0; neg = 0; if (str[0] == '-') { neg = 1; str ++; } if (str[0] == '0') { switch (str[1]) { case 'b': case 'B': str += 2; base = 2; break; case 'o': case 'O': str += 2; base = 8; break; case 't': case 'T': str += 2; base = 10; break; case 'x': case 'X': str += 2; base = 16; break; } } val = strtoq(str,&sp,base); if ((sp == str) || *sp) return(0); *ip = neg ? -val : val; return(1); } static int interpret_float(const char *s, double *vp) { double v; char *ep; v = strtod(s,&ep); if ((ep == s) || *ep) return(0); *vp = v; return(1); } static void massage(unsigned char *s) { unsigned char *f; unsigned char *t; static unsigned char map[] = "a\7b\be\33f\fn\nr\rt\t\0\0"; f = s; t = f; while (*f) { if (*f == '\\') { int i; switch (*++f) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': i = *f++ - '0'; if ((*f >= '0') && (*f <= '7')) { i = (i << 3) + *f++ - '0'; if ((*f >= '0') && (*f <= '7')) { i = (i << 3) + *f++ - '0'; } } *t++ = i & 0xff; break; case 'x': case 'X': i = 0; while (index("0123456789abcefABCDEF",*++f)) { i <<= 4; switch (*f) { case '0' ... '9': i += *f - '0'; break; case 'a': case 'A': i += 10; break; case 'b': case 'B': i += 11; break; case 'c': case 'C': i += 12; break; case 'd': case 'D': i += 13; break; case 'e': case 'E': i += 14; break; case 'f': case 'F': i += 15; break; } } *t++ = i; break; case '-': f ++; break; default: for (i=0;map[i];i+=2) { if (*f == map[i]) { f ++; *t++ = map[i+1]; break; } } if (! map[i]) { *t++ = *f++; } break; } } else { *t++ = *f++; } } *t++ = '\0'; } static void print_digits(LLI num, int pad, int base, char padc) { static char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz"; int dig; if (num == 0) { for (;pad>0;pad--) putchar(padc); return; } if (base < 0) { base = - base; dig = num % base; if (dig < 0) dig += base; print_digits((dig-num)/base,pad-1,-base,padc); } else if (num < 0) { if (padc == '0') { putchar('-'); print_digits(-num,pad-1,base,padc); return; } else if (-num < base) { print_digits(0,pad-2,base,padc); putchar('-'); dig = - num; } else { num = - num; print_digits(-(num/base),pad-1,base,padc); dig = num % base; } } else { print_digits(num/base,pad-1,base,padc); dig = num % base; } putchar(digits[dig]); } static void print_num(LLI num, int pad, int base, char padc) { if (num == 0) { for (pad--;pad>0;pad--) { putchar(padc); } putchar('0'); } else { print_digits(num,pad,base,padc); } } static void delaywait(void) { struct timeval now; struct timeval delta; delaynext.tv_sec += delayinc.tv_sec; delaynext.tv_usec += delayinc.tv_usec; if (delaynext.tv_usec >= 1000000) { delaynext.tv_usec -= 1000000; delaynext.tv_sec ++; } fflush(0); while (1) { gettimeofday(&now,0); if ( (now.tv_sec > delaynext.tv_sec) || ( (now.tv_sec == delaynext.tv_sec) && (now.tv_usec >= delaynext.tv_usec) ) ) return; if (now.tv_usec <= delaynext.tv_usec) { delta.tv_usec = delaynext.tv_usec - now.tv_usec; delta.tv_sec = delaynext.tv_sec - now.tv_sec; } else { delta.tv_usec = delaynext.tv_usec + 1000000 - now.tv_usec; delta.tv_sec = delaynext.tv_sec - 1 - now.tv_sec; } if ((delta.tv_sec == 0) && (delta.tv_usec == 0)) delta.tv_usec = 1; select(0,0,0,0,&delta); } } static void syncrounddown(void) { ULLI dn; ULLI di; dn = (delaynext.tv_sec * 1000000ULL) + delaynext.tv_usec; di = (delayinc.tv_sec * 1000000ULL) + delayinc.tv_usec; dn = ((dn - 1) / di) * di; delaynext.tv_sec = dn / 1000000ULL; delaynext.tv_usec = dn % 1000000ULL; } static void delaysetup(void) { if (delay < 0) { fprintf(stderr,"%s: negative delay time\n",__progname); exit(1); } if (delay == 0) { havedelay = 0; return; } delayinc.tv_sec = delay; if (delayinc.tv_sec > delay) delayinc.tv_sec --; delayinc.tv_usec = (delay - delayinc.tv_sec) * 1000000; if (delayinc.tv_usec < 0) { delayinc.tv_usec += 1000000; delayinc.tv_sec --; } else if (delayinc.tv_usec >= 1000000) { delayinc.tv_usec -= 1000000; delayinc.tv_sec ++; } if ((delayinc.tv_sec == 0) && (delayinc.tv_usec == 0)) delayinc.tv_usec = 1; gettimeofday(&delaynext,0); if (havesync) { syncrounddown(); delaywait(); } } static void printnum(LLI n) { if (havedelay) { if (firstnum) delaysetup(); else delaywait(); } fputs(prefix,stdout); print_num(havemodulus?(n%modulus):n,pad,base,have0pad?'0':' '); fputs(postfix,stdout); firstnum = 0; } /* Mathematical modulus (eg, mod(-10,3) -> 2) a may be +ve or -ve; b must be +ve */ static LLI mod(LLI a, LLI b) { return( ( (a<0) ? b-((-a)%b) : a ) % b ); } /* Integer division that rounds towards -ve infinity */ static LLI div_mi(LLI a, LLI b) { return( (a >= 0) ? a/b : -1-((-1-a)/b) ); } /* Integer division that rounds towards +ve infinity */ static LLI div_pi(LLI a, LLI b) { return( (a > 0) ? ((a-1)/b)+1 : -((-a)/b) ); } static LLI extgcd(LLI a, LLI b, LLI *ax, LLI *bx) { /* Invariants (oa, ob = original a, b) a = oa * tax + ob * tay b = oa * tbx + ob * tby Init: a = oa, b = ob, tax = 1, tay = 0, tbx = 0, tby = 1 Each cycle: q = a / b, r = a % b If r = 0, done: b is gcd, tbx/tby are factors a' = b, tax' = tbx, tay' = tby b' = r, tbx' = tax - (q * tbx), tby' = tay - (q * tby) (foo' is next cycle's foo) */ LLI tax; LLI tay; LLI tbx; LLI tby; LLI q; LLI r; LLI t; tax = 1; tay = 0; tbx = 0; tby = 1; while (1) { q = a / b; r = a - (b * q); /* a%b */ if (! r) { *ax = tbx; *bx = tby; return(b); } a = b; b = r; t = tax - (q * tbx); tax = tbx; tbx = t; t = tay - (q * tby); tay = tby; tby = t; } } int main(int, char **); int main(int ac, char **av) { LLI lli; int i; int forced; int type; for (i=0;i (ac--,av++;ac;ac--,av++) { if (! forced) { for (i=0;i; } } fprintf(stderr,"%s: unrecognized value tag %s\n",__progname,*av); continue <"args">; } switch (vars[type].kind) { case bigint: if (! interpret_number(*av,vars[type].var)) { fprintf(stderr,"%s: bad number %s\n",__progname,*av); errs ++; } else { *vars[type].have = 1; } break; case integer: if (! interpret_number(*av,&lli)) { fprintf(stderr,"%s: bad number %s\n",__progname,*av); errs ++; } else { i = lli; if (i != lli) { fprintf(stderr,"%s: out-of-range number %s\n",__progname,*av); errs ++; } else { *(int *)vars[type].var = i; *vars[type].have = 1; } } break; case string: massage(*av); *(const char **)vars[type].var = *av; *vars[type].have = 1; break; case floating: if (! interpret_float(*av,vars[type].var)) { fprintf(stderr,"%s: bad number %s\n",__progname,*av); errs ++; } else { *vars[type].have = 1; } break; case novalue: abort(); break; } forced = 0; } if (errs) { fprintf(stderr,"\ Usage: %s [keyword value] [keyword value]...\n\ Keywords are:",__progname); for (i=0;i stop)) { fprintf(stderr,"%s: with `random', `from' must be less than `to'\n",__progname); exit(1); } if (! havestart) { if (havestop && (stop < 0)) { fprintf(stderr,"%s: with `random' and a negative `to', `from' must be given\n",__progname); exit(1); } start = 0; havestart = 1; } if (! havestop) { stop = (~(ULLI)0) >> 1; havestop = 1; } } if (! havestart) { if ( (haveby && (by < 0)) || (havestop && (stop < 0)) ) { start = -1; } else { start = 1; } havestart = 1; } if (!haveby && !haverandom) { if (havestop && (stop < start)) { by = -1; } else { by = 1; } haveby = 1; } if (! (havepad || have0pad)) { pad = 1; havepad = 1; } if (! haveprefix) { prefix = ""; haveprefix = 1; } if (! havepostfix) { postfix = "\n"; havepostfix = 1; } if (! havebase) { basename = "10"; havebase = 1; } base = 0; for (i=0;bases[i].name;i++) { if (strcmp(basename,bases[i].name) == 0) { base = bases[i].base; break; } } if (base == 0) { LLI lli; if (!interpret_number(basename,&lli) || ((base=lli) != lli)) { base = 0; } } if ((abs(base) < 2) || (abs(base) > 36)) { fprintf(stderr,"%s: bad base `%s'\n",__progname,basename); exit(1); } firstnum = 1; if (havemultof) { if (multof < 0) multof = - multof; } else { multof = 1; } if (haverandom) { /* * This code depends, for correctness when the range approaches * half the range of LLI/ULLI, on two's-complement representation. * This probably could be fixed, but it would be a fair bit of * work. */ ULLI r; ULLI mul; ULLI add; ULLI mask; ULLI (*gen)(void); ULLI gen_any(void) { ULLI v; ULLI m; m = ~(ULLI)0; while (m) { v = (v << 24) ^ random(); m >>= 24; } return(v); } ULLI gen_mod(void) { return(gen_any()%r); } ULLI gen_mask(void) { ULLI v; while (1) { v = gen_any() & mask; if (v < r) return(v); } } if (stop < start) abort(); if (havemultof && (multof != 1)) { ULLI start0; ULLI stop0; start0 = start; stop0 = stop; if (start % multof) { start += multof - (start % multof); } stop -= stop % multof; if (stop < start) { fprintf(stderr,"%s: no multiples of %lld occur between %lld and %lld\n",__progname,multof,start0,stop0); exit(1); } mul = multof; r = 1 + (ULLI)(stop/mul) - (ULLI)(start/mul); } else { r = 1 + (ULLI)stop - (ULLI)start; mul = 1; } add = start; srandom(time(0)); if (r == 0) /* 1+ overflowed - special case */ { gen = &gen_any; } else if (r < (~(ULLI)0)>>17) { gen = &gen_mod; } else { gen = &gen_mask; mask = r - 1; while ((mask+1) & mask) mask |= mask >> 1; } for (;!havencount||(ncount>0);ncount--) { printnum(((*gen)()*mul)+add); } } else if (havestop && (stop == start)) { if (! (start % multof)) printnum(start); } else { /* Chinese Remainder Theorem time. The generalized CRT says that given a set of congruences V = A[i] mod N[i], a solution V exists iff A[i] = A[j] mod gcd(N[i],N[j]) for all (i,j). (The non-generalized CRT is the same but with the additional condition gcd(N[i],N[j])==1 whenever i!=j.) For the non-generalized CRT, there is a construction for V (probably extensible to the generalized CRT, but we don't need that). Let NP=product(N[i]); let NN[i]=NP/N[i]. Use the extended Euclidean GCD algorithm on N[i] and NN[i] to compute F[i] and G[i] such that F[i]N[i]+G[i]NN[i]=1. Let E[i]=G[i]NN[i]. Then E[i]=1-F[i]N[i], so E[i]=1 mod N[i]. Let V be sum(A[i]E[i]). Then V mod N[i] is A[i] from the [i] term (because E[i] mod N[i] = 1) and 0 from all other terms (because N[i] divides NN[j] for i!=j), so it satisfies the congruences. For our purposes, we appear to want the generalized CRT, but we have only two congruences (k = start%by mod by, and k = 0 mod multof) and we can divide everything through by f=gcd(by,multof) - we check that start is a multiple of f, because otherwise there is no solution. This leads to a non-generalized CRT problem A[0] = (start/f) % (by/f) N[0] = by/f A[1] = 0 N[1] = multof/f The EEGCD gives us X and Y such that by*X+multof*Y=f, or, equivalently, (by/f)*X+(multof/f)*Y=1, while computing f. Then, in the notation above, NN[0]=multof/f, NN[1]=by/f, F[0]=G[1]=X, G[0]=F[1]=Y, and our solution is A[0]NN[0]G[0]+A[1]NN[1]G[1]. But A[1] is 0, so the second term vanishes, leaving us with just A[0]NN[0]G[0], or ((start/f)%(by/f))*(multof/f)*Y (remember, NN[0] = N[1]). But this is the solution to the everything-divided-by-f problem, so we have to multiply it by f to to get the solution we need. We do this by computing Y*(multof/f)*(start%by) - except that start may be of the opposite sign from by, so (except for the start%f check), we have to use mod() and div_Xi() rather than % and / when dealing with start. (We might be able to use % and /, but trying to work that out makes my brain hurt, and for pre-loop setup code the extra cost of using mod() and div_Xi() is ignorable.) */ LLI f; LLI m; LLI x; LLI y; LLI v; if (by < 0) { f = extgcd(-by,multof,&x,&y); if (! (start % f)) { m = ((-by) / f) * multof; v = y * (multof / f) * mod(-start,-by); v = mod(v,m); if (v < mod(-start,m)) v += m; start = (div_pi(start,m) * m) - v; by = - m; for (lli=start;!havestop||(lli>=stop);lli+=by) { printnum(lli); } } } else if (by > 0) { f = extgcd(by,multof,&x,&y); if (! (start % f)) { m = (by / f) * multof; v = y * (multof / f) * mod(start,by); v = mod(v,m); if (v < mod(start,m)) v += m; start = (div_mi(start,m) * m) + v; by = m; for (lli=start;!havestop||(lli<=stop);lli+=by) { printnum(lli); } } } else { if (! (start % multof)) { while (1) { printnum(start); } } } } exit(0); }