| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| /* |
| * Utility for simple interfacing with the "TestU01" library: |
| * http://simul.iro.umontreal.ca/testu01/tu01.html |
| * |
| * It reads from its standard input an infinite sequence of 32-bits |
| * integers and runs one of the test suites "SmallCrush", "Crush" or |
| * "BigCrush". |
| * "TestU01" writes its report to standard output. |
| */ |
| |
| #include <stdint.h> |
| #include <unistd.h> |
| #include <string.h> |
| |
| /* |
| * Use this flag to switch the includes for TestU01. |
| * - An install from the TestU01 source puts headers directly |
| * into the <install directory> (e.g. /usr/local/include). |
| * - The linux package install uses a testu01 sub-directory. |
| */ |
| #define TEST_U01_SRC 0 |
| |
| #if TEST_U01_SRC |
| #include <unif01.h> |
| #include <bbattery.h> |
| #include <util.h> |
| #else |
| #include <testu01/unif01.h> |
| #include <testu01/bbattery.h> |
| #include <testu01/util.h> |
| #endif |
| |
| #define TU_S "SmallCrush" |
| #define TU_C "Crush" |
| #define TU_B "BigCrush" |
| #define T_RAW_32 "raw32" |
| #define T_RAW_64 "raw64" |
| #define BUFFER_LENGTH 2048 |
| |
| typedef struct { |
| uint32_t buffer[BUFFER_LENGTH]; |
| uint32_t index; |
| } StdinReader_state; |
| |
| /* Lookup table for binary representation of bytes. */ |
| const char *bit_rep[16] = { |
| [ 0] = "0000", [ 1] = "0001", [ 2] = "0010", [ 3] = "0011", |
| [ 4] = "0100", [ 5] = "0101", [ 6] = "0110", [ 7] = "0111", |
| [ 8] = "1000", [ 9] = "1001", [10] = "1010", [11] = "1011", |
| [12] = "1100", [13] = "1101", [14] = "1110", [15] = "1111", |
| }; |
| |
| /* |
| * Print a binary string representation of the 8-bits of the byte to stdout. |
| * |
| * 01101101 |
| */ |
| void printByte(uint8_t byte) |
| { |
| printf("%s%s", bit_rep[byte >> 4], bit_rep[byte & 0x0F]); |
| } |
| |
| /* |
| * Print a string representation of the 4 bytes of the 32-bit unsigned integer |
| * to stdout on a single line using: a binary string representation of |
| * the bytes; the unsigned integer; and the signed integer. |
| * |
| * 11001101 00100011 01101111 01110000 3441651568 -853315728 |
| */ |
| void printInt(uint32_t value) |
| { |
| /* Write out as 4 bytes with spaces between them, high byte first. */ |
| printByte((uint8_t)((value >> 24) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)((value >> 16) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)((value >> 8) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)( value & 0xff)); |
| /* Write the unsigned and signed int value */ |
| printf(" %10u %11d\n", value, (int32_t) value); |
| } |
| |
| /* |
| * Print a string representation of the 8 bytes of the 64-bit unsigned integer |
| * to stdout on a single line using: a binary string representation of |
| * the bytes; the unsigned integer; and the signed integer. |
| * |
| * 10011010 01010011 01011010 11100100 01000111 00010000 01000011 11000101 11120331841399178181 -7326412232310373435 |
| */ |
| void printLong(uint64_t value) |
| { |
| /* Write out as 8 bytes with spaces between them, high byte first. */ |
| printByte((uint8_t)((value >> 56) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)((value >> 48) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)((value >> 40) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)((value >> 32) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)((value >> 24) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)((value >> 16) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)((value >> 8) & 0xff)); |
| putchar(' '); |
| printByte((uint8_t)( value & 0xff)); |
| /* Write the unsigned and signed int value */ |
| printf(" %20lu %20ld\n", value, (int64_t) value); |
| } |
| |
| unsigned long nextInt(void *par, |
| void *sta) { |
| static size_t last_read = 0; |
| |
| StdinReader_state *state = (StdinReader_state *) sta; |
| if (state->index >= last_read) { |
| /* Refill. */ |
| last_read = fread(state->buffer, sizeof(uint32_t), BUFFER_LENGTH, stdin); |
| if (last_read != BUFFER_LENGTH) { |
| // Allow reading less than the buffer length, but not zero |
| if (last_read == 0) { |
| // Error handling |
| if (feof(stdin)) { |
| // End of stream, just exit. This is used for testing. |
| exit(0); |
| } else if (ferror(stdin)) { |
| // perror will contain a description of the error code |
| perror("[ERROR] Failed to read stdin"); |
| exit(1); |
| } else { |
| printf("[ERROR] No data from stdin\n"); |
| exit(1); |
| } |
| } |
| } |
| state->index = 0; |
| } |
| |
| uint32_t random = state->buffer[state->index]; |
| ++state->index; /* Next request. */ |
| |
| return random; |
| } |
| |
| double nextDouble(void *par, |
| void *sta) { |
| return nextInt(par, sta) / 4294967296.0; |
| } |
| |
| static void dummy(void *sta) { |
| printf("N/A"); |
| |
| return; |
| } |
| |
| unif01_Gen *createStdinReader(void) { |
| unif01_Gen *gen; |
| StdinReader_state *state; |
| size_t len; |
| char name[60]; |
| |
| state = util_Malloc(sizeof(StdinReader_state)); |
| |
| gen = util_Malloc(sizeof(unif01_Gen)); |
| gen->state = state; |
| gen->param = NULL; |
| gen->Write = dummy; |
| gen->GetU01 = nextDouble; |
| gen->GetBits = nextInt; |
| |
| strcpy(name, "stdin"); |
| len = strlen(name); |
| gen->name = util_Calloc(len + 1, sizeof (char)); |
| strncpy(gen->name, name, len); |
| |
| // Read binary input. |
| freopen(NULL, "rb", stdin); |
| state->index = BUFFER_LENGTH; |
| |
| return gen; |
| } |
| |
| void deleteStdinReader(unif01_Gen *gen) { |
| gen->state = util_Free(gen->state); |
| gen->name = util_Free(gen->name); |
| util_Free(gen); |
| } |
| |
| int main(int argc, |
| char **argv) { |
| unif01_Gen *gen = createStdinReader(); |
| char *spec = argv[1]; |
| |
| if (argc < 2) { |
| printf("[ERROR] Specify test suite: '%s', '%s' or '%s'\n", TU_S, TU_C, TU_B); |
| exit(1); |
| } else if (strcmp(spec, TU_S) == 0) { |
| bbattery_SmallCrush(gen); |
| } else if (strcmp(spec, TU_C) == 0) { |
| bbattery_Crush(gen); |
| } else if (strcmp(spec, TU_B) == 0) { |
| bbattery_BigCrush(gen); |
| } else if (strcmp(spec, T_RAW_32) == 0) { |
| /* Print to stdout until stdin closes. */ |
| while (1) { |
| printInt(nextInt(0, gen->state)); |
| } |
| } else if (strcmp(spec, T_RAW_64) == 0) { |
| /* Detect endianness required to join two 32-bit values. */ |
| uint32_t val = 0x01; |
| /* |
| * Use a raw view of the bytes with a char* to determine if |
| * the first byte is unset (big endian) or set (little endian). |
| */ |
| char * buff = (char *)&val; |
| |
| int littleEndian = (buff[0] != 0); |
| |
| /* Print to stdout until stdin closes. */ |
| while (1) { |
| /* Read 2 values. */ |
| uint64_t hi = nextInt(0, gen->state); |
| uint64_t lo = nextInt(0, gen->state); |
| if (littleEndian) { |
| printLong((lo << 32) | hi); |
| } else { |
| printLong((hi << 32) | lo); |
| } |
| } |
| } else { |
| printf("[ERROR] Unknown specification: '%s'\n", spec); |
| exit(1); |
| } |
| |
| deleteStdinReader(gen); |
| return 0; |
| } |