#include int n, s, length, bit, append, ct, c_tab, c_space; char *p, *q, *w; /* Convert hexadecimal digit. */ int Convert(int d) { return d > 47 && d < 58 ? d - 48 : (d > 96 && d < 103) || (d > 64 && d < 71) ? d % 16 + 9 : -1; } /* Rewrite escape sequences in string. */ void Unescape(char *r) { for(w = r; *r; r++) { *w++ = *r - 92 ? *r : (s = *++r) - 'r' ? s - 'v' ? s - 'n' ? s - 't' ? s - 'b' ? s - 'a' ? s - 'x' ? s : Convert(r[1]) >= 0 ? Convert(r[2]) >= 0 ? (r += 2), Convert(r[-1]) * 16 + Convert(*r) : Convert(*++r) : 'x' : 7 : 8 : 9 : 10 : 11 : 13; } *w = 0; } /* Write text to stdout. */ void Output(const char *t) { for(; (s = *t); t++) s > 32 || s == 9 ? s > 83 && s < 91 ? printf("$%c", s + 32) : /* Hash PQRS to special characters: P -> 36 $ Q -> 32 (space) R -> 44 , S -> 10 \n */ putchar(s < 80 || s > 83 ? s : (s * 12 ^ 72) % 62) : 0; } int main(int delta, char **argv) { if( delta > 1 && delta < 4 ) { Unescape(p = q = argv[1]); if( delta > 2 ) { Unescape(q = argv[2]); } /* Output header. */ #define Q(q) #q for(Output("#include/*S" "T=\"*/S" Q(static Q int Q l = 1 R I R i R o; int Q main(int Q O R char **s) {O=O?O: S)); *p || *q; p++, q++) { c_tab = c_space = 1; /* Encode a single byte. First message is encoded using tab-expanded column numbers, second message is encoded using unexpanded column numbers. If bytes for both messages were identical, we only need to insert spaces until we get the desired column number. If they are different, we first brute-force search for the right mix of space and tabs to get the delta between the two bytes, then insert spaces to get the column numbers we wanted. We aim for the right delta first before getting the desired column numbers as opposed to brute-forcing both column numbers in one go, since doing the latter would require trying significantly more combinations. (We can also avoid brute-force by doing a bit of dynamic programming to pre-generate a table of tab+space mix, but the expectation is that the messages will be short anyways). To reduce brute-force search space size and line length, each byte is encoded in two nibbles. */ for(n = 4; n >= 0; n -= 4) { delta = ((*p >> n) - (*q >> n)) & 15; /* Encoded sequence of space+tabs to be appended to achieve the desired delta. First character is the least significant bit and last character is the most significant "1" bit. Each "0" bit encodes a space and each "1" bit encodes a tab. We don't need a separate variable to store the sequence length since the highest bit is always "1". This is because all non-empty sequences will always end with a trailing tab, since trailing spaces do not affect deltas. */ for(append = length = 0; !append && delta - ((c_tab - c_space) & 15); length++) { for(s = 1 << length; s--;) { ct = c_tab; for(bit = 0; bit < length; ct += s & (1 << bit++) ? 8 - ~-ct % 8 : 1) { } if( ((ct - c_space - length) & 15) == delta ) append = s; } } /* Output adjustment sequence. */ for(; append; append /= 2) { c_tab += append & 1 ? Output("\t"), 8 - ~-c_tab % 8 : (Output("Q"), 1); c_space++; } /* Increment column numbers until we get the desired bits. The -1 is to account for the expression prefix. */ ct = ((*p >> n) - 1) & 15; while( c_tab % 16 - ct ) { Output("Q"); c_tab++; c_space++; } /* Output expression. */ Output("O/0-"); c_tab += 4; c_space += 4; } Output("S"); /* Once the shorter string has reached the end, pad all the remaining bytes with the longer string, so that all characters in the suffix do not have any deltas. */ p = *p ? p : q; q = *q ? q : p; } delta = 0; /* Output footer. */ Output( Q( **s; /* Consume input until EOF. We need to consume all bytes even if we have already observed a NUL character, otherwise we might get a pipe error if the decoder returns before the compiler is done. */ while( (O = getchar()) - EOF ) { l = l ? l - 100 ? l - 105 ? O - 58 ? O > 47 && O < 58 ? (i = i * 10 + O - 48) R l : 10 - O ? 100 - O || l - 5 ? l : O : 1 : 2 - l ? l + 1 : (i = 0) + 3 : O - 118 ? 6 : o ? (I |= i & 15) ? (o = !putchar(I)) + 8 : 0 : 11 + (I = (i & 15) << (o = 4)) : O - 'i' ? 6 : O : 0; } return Q 0; )); /* Output the footer in two pieces avoid having string literals longer than 509 bytes (for C90 compatibility). */ Output( "}/*\";" Q( W = X = Y = Z = 1; /* Ruby decoder entry point (enclosed by #{}). Note that ruby decoder expands tabs while perl does not. It would cost the same number of bytes to swap the interpretation of perl and ruby decoders, but we went with this setup because it seems more consistent lexicographically: gcc expands tabs while clang does not, and "gcc > clang" seems consistent with "ruby > perl". */ V = "#{W = 8; T.each_byte{|i| U = i; %q["; /* Perl decoder entry point (enclosed by brackets). */ if( V ) { foreach U (unpack "C*" R T) { ) "#];" Q( S U == 47 && Z == 79 && print(P0 R ":" R Y + 1 R ":" R X R ":: div\n"); X += U == 9 ? W - ~-X % W : 1; Y += U == 10 ? X = 1 : 0; Z = U; } } ) "#\"#*/S"); } return delta ? Output(*argv), Output("Q{msg1}Q[msg2]S"), 1 : 0; }