use strict; use warnings; use Inline 'C'; use constant ZERO_START => 0; # digit-sequence allows 0 start use constant NON_ZERO_START => 1; # digit-sequence must not start with a leading 0 msg_subst_seed((time() + $$) % 32000); # just for tests, not a good idea where security matters do { my $x = msg_subst("3x: ({\\d4})x({\\d1})x({\\d10})", NON_ZERO_START); print "[$x]\n"; }; print msg_subst("empty: ({\\d0})\n", ZERO_START); print msg_subst("$_-dig: ({\\d$_})\n", ZERO_START) for (1..10); print msg_subst("2x : ({\\d3}) x ({\\d3})\n", NON_ZERO_START); print msg_subst("huge: ({\\d99})\n", ZERO_START); print msg_subst("err: ({\\d100})\n", ZERO_START); print msg_subst("err: ({\\d-10})\n", ZERO_START); print msg_subst('overflow: {\d99}{\d99}{\d99}{\d99}{\d99}{\d99}{\d99}{\d99}{\d99}{\d99}{\d99}'."\n", ZERO_START); __END__ __C__ #include /* see: http://stackoverflow.com/questions/1167253/implementation-of-rand */ static uint32_t z1 = 12345, z2 = 12345, z3 = 12345, z4 = 12345; /* seed */ void msg_subst_seed(int seed) { /* TODO: needs improvement */ if (seed < 0) seed = -seed; if (!seed) seed = 1; z1 = seed; /* z1: positive and >= 1 */ } uint32_t lfsr113_Bits (void) { uint32_t b; b = ((z1 << 6) ^ z1) >> 13; z1 = ((z1 & 4294967294U) << 18) ^ b; b = ((z2 << 2) ^ z2) >> 27; z2 = ((z2 & 4294967288U) << 2) ^ b; b = ((z3 << 13) ^ z3) >> 21; z3 = ((z3 & 4294967280U) << 7) ^ b; b = ((z4 << 3) ^ z4) >> 12; z4 = ((z4 & 4294967168U) << 13) ^ b; return (z1 ^ z2 ^ z3 ^ z4); } /* see.. until here */ char get_digit() {/* iterator to get an ASCII digit in range '0'..'9', the naive way... */ static int count = 0; static uint32_t drawn_rand; char digit; if (!count) { drawn_rand = lfsr113_Bits(); count = 8; } digit = (char) ('0' + drawn_rand % 10); drawn_rand /= 10; count--; return digit; } SV * msg_subst(char* msg, int mode) { static char buf[1024]; /* keep the result smaller than this, increase the static buffer, or use malloc() */ char *to = buf; char *from = msg; while(*from && (to-buf) <= 1000) { /* for simplicity, we allow {\d0} .. {\d99} only */ if (*from == '{' && from[1] == '\\' && from[2] == 'd' && isdigit( from[3] )) { int i; int count = from[3] - '0'; int consumed = 4; if ( isdigit(from[4]) ) { count = count * 10 + from[4] - '0'; consumed++; } if ( from[consumed] == '}' ) { /* found a valid {\d##} sequence */ if (count && mode == 1) { count--; *to = get_digit(); while (*to == '0') { *to = get_digit(); } /* no leading zeros wanted */ to++; } for (i=0; i= 1000 ) strcpy( to, "... *OVERFLOW*!\n"); return newSVpv(buf, strlen(buf)); } /* further improvements: - profile / this alternative "can" be faster - other/better random generator or lookup-table () - parse pattern once (if pattern stays constant for a sufficiently long period of time) - more than 99 digits - Modes: HEX, ASCII, SET(...), RANGE(...) - tweak "use inline C;" - pre-compute messages if possible - return a list of results - find more buffer overflows ;-) - find mem-leaks? - set $! - ... */ #### [3x: (5800)x(9)x(4119272153)] empty: () 1-dig: (6) 2-dig: (00) 3-dig: (286) 4-dig: (3538) 5-dig: (76912) 6-dig: (152922) 7-dig: (1998601) 8-dig: (46526790) 9-dig: (272269142) 10-dig: (5036180257) 2x : (270) x (295) huge: (606982119713516463256624381450768829776742640836318917840149816984333515486911733872823592611980610) err: ({\d100}) err: ({\d-10}) overflow: 3883379130145185720790856556823529236852687202003993798722253099376966524016525788747490782593284184689609244124713363335917258666107267540408402492579245495755362814710529958180257677426223764158638639334500419562399159163492959887043676219576227471704453768824278868363680753011971637881719102124666151892149212534575264402401302876428772975931871894585878002192701697051196363120204722836907121681233511128999255472047015971894132132723455513141549167471400425064361942503605367300481794869519467985721115755886755136374045044219384244506458722427122395842188661791384989969881810425465047226552594411502648206569604159093565820975417427431171140585817738954559080595466953448973618831534358081508526701800889225689614671600253384601792439219879764410043155132680359897548808738466227306596386102262825384142976583651809653423651815184137091471377911310352705521461780968180647033328696962090056923840419103952885318874659996497513072706270697538310675102369072243267355810846576590914699... *OVERFLOW*!