-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdist.c
143 lines (125 loc) · 3.01 KB
/
dist.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
/* vim: set ts=4 sw=4 noexpandtab: */
/*************************************************************************
* dist.c -- print a histogram of the distribution of characters in the
* incoming stream (or file passed as argv[1]) to do a very
* cursory, crappy, and insecure check for randomness!
*
************************************************************************/
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <getopt.h>
#include <unistd.h>
#include <stdbool.h>
#include <signal.h>
#include <errno.h>
#include "cmdlineparse.h"
uint64_t *arr = NULL;
char bitcount = 8;
char *file = NULL;
bool done = false;
/* Set the configuration options above from cmdline */
static void initialize_options(int argc, char *argv[])
{
int c;
while((c=getopt(argc, argv, "+hb:")) != -1) {
switch(c) {
case 'b':
switch(bitcount = parse_num(c)) {
case 1:
bitcount = 1;
break;
case 4:
bitcount = 4;
break;
case 8:
bitcount = 8;
break;
default:
fprintf(stderr, "Error, bit count needs to be '1', '4', or '8'\n");
exit(EXIT_FAILURE);
}
break;
case 'h':
fprintf(stderr,
"Usage: %s [options] [FILE] \n\
FILE file or device to read (default is stdin)\n\
Options:\n\
-b Bit-length, valid values are 1, 4, and 8\n\
", argv[0]);
exit(EXIT_SUCCESS);
case '?':
if(strchr("bh", optopt) == NULL)
fprintf(stderr,
"Unknown option -%c encountered\n", optopt);
else
fprintf(stderr,
"Option -%c requires an argument\n", optopt);
exit(EXIT_FAILURE);
default:
abort();
}
}
if(optind + 1 == argc) {
file = argv[optind];
return;
} else if (optind + 1 < argc) {
fprintf(stderr, "Error, extra arguments found starting with: %s\n",
argv[optind + 1]);
exit(EXIT_FAILURE);
}
}
static void on_term(int sig)
{
sig++;
done = true;
printf("\n");
}
int main(int argc, char *argv[])
{
FILE *fp = stdin;
unsigned char buf[4096];
uint64_t total = 0;
uint64_t norm = 0;
uint64_t max = 0;
size_t n;
initialize_options(argc, argv);
arr = calloc((1 << bitcount), sizeof(uint64_t));
signal(SIGINT, on_term);
if(file != NULL) {
if((fp = fopen(argv[1], "r")) == NULL) {
fprintf(stderr, "Error opening %s\n", argv[1]);
return 1;
}
}
while((n = fread(buf, 1, sizeof(buf), fp)) != 0 && !done) {
for(size_t i = 0; i < n; i++)
for(int j = 0; j < 8; j += bitcount)
arr[(buf[i] >> j) & ((1 << bitcount) - 1)]++;
total += n;
}
if(ferror(fp) && errno != EINTR) {
fprintf(stderr, "File error occured\n");
return 1;
}
fclose(fp);
for(int i = 0; i < (1 << bitcount); i++) {
if(arr[i] > max)
max = arr[i];
norm += arr[i];
}
if(max == 0)
return 1;
for(int j = 0; j < (1 << bitcount); j++) {
int stat;
stat = (60 * arr[j]) / max;
printf("0x%.2x (%8.5f%%) |", j, 100.0f * (double)arr[j] / (double)norm);
for(int k = 0; k < stat; k++) {
putchar('*');
}
printf("\n");
}
printf("%lu bytes read total\n", total);
return 0;
}