-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathiocccsize.c
219 lines (200 loc) · 6.68 KB
/
iocccsize.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
/*
* iocccsize - IOCCC Source Size Tool
*
* "You are not expected to understand this" :-)
*
* Public Domain 1992, 2015, 2018, 2019, 2021 by Anthony Howe. All rights released.
* With IOCCC mods in 2019-2023, 2025 by chongo (Landon Curt Noll) ^oo^
*
* SYNOPSIS
*
* usage: iocccsize [-h] [-i] [-v level] [-V] prog.c
* usage: iocccsize [-h] [-i] [-v level] [-V] < prog.c
*
* -i ignored for backward compatibility
* -h print usage message in stderr and exit 2
* -v level set debug level (def: none)
* -V print version and exit 3
*
* Exit codes:
* 0 source code is within Rule 2a and Rule 2b limits
* 1 source code larger than Rule 2a and/or Rule 2b limits
* 2 -h used and help printed
* 3 -V used and version printed
* 4 invalid command line
* 6 there is no Rule 6!
* >= 10 some internal error occurred
*
* DESCRIPTION
*
* By default, the Rule 2b count is written to stdout.
* If the debug level is > 0, then the Rule 2a, Rule 2b,
* and keyword count is written to stdout instead.
*
* The entry's gross size in bytes must be less than equal to the
* RULE_2A_SIZE value as defined in soup/limit_ioccc.h.
*
* The entry's net size in bytes must be less than equal to the
* RULE_2B_SIZE value as defined in soup/limit_ioccc.h.
*
* The size tool counts most C reserved words (keyword, secondary,
* and selected preprocessor keywords) as 1. The size tool counts all
* other octets as 1 excluding ASCII whitespace, and excluding any
* ';', '{' or '}' followed by ASCII whitespace, and excluding any
* ';', '{' or '}' octet immediately before the end of file.
*/
/*
* IOCCC Judge's remarks:
*
* This code contains undocumented features. On the other hand, this code
* is RTFS (for certain values of RTFS). One might say that this code
* perfectly documents itself. :-)
*
* Many thanks to Anthony Howe for taking the time to put his OCD
* (Obfuscated Coding Determination) into this code!
*/
#include <ctype.h>
#include <getopt.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <locale.h>
#if defined(MKIOCCCENTRY_USE)
/*
* limit_ioccc - IOCCC size and rule related limitations
*/
#include "soup/iocccsize_err.h"
#include "soup/limit_ioccc.h"
#include "soup/location.h"
#else /* MKIOCCCENTRY_USE */
#include "iocccsize_err.h"
#endif /* MKIOCCCENTRY_USE */
#include "iocccsize.h"
/*
* usage message, split into strings that are small enough to be supported by C standards
*/
static char usage0[] =
"usage: iocccsize [-h] [-i] [-v level] [-q] [-V] prog.c\n"
"usage: iocccsize [-h] [-i] [-v level] [-q] [-V] < prog.c\n"
"\n"
"\t-i\t\tignored for backward compatibility\n"
"\t-h\t\tprint usage message in stderr and exit\n"
"\t-v level\tset debug level (def: none)\n"
"\t-q\t\tquiet mode: silence msg(), warn(), warnp() if -v 0 (def: not msg_warn_silent)\n"
"\t-V\t\tprint version and exit\n"
"\n";
static char usage1[] =
"\tBy default, the Rule 2b count is written to stdout.\n"
"\tIf the debug level is > 0, then the Rule 2a, Rule 2b,\n"
"\tand keyword count is written to stdout instead.\n"
"\n"
"Exit codes:\n"
" 0 source code is within Rule 2a and Rule 2b limits\n"
" 1 source code larger than Rule 2a and/or Rule 2b limits\n"
" 2 -h used and help printed\n"
" 3 -V used and version printed\n"
" 4 invalid command line\n"
" 6 there is no Rule 6!\n"
" >= 10 some internal error occurred\n";
int
main(int argc, char **argv)
{
extern char *optarg; /* option argument */
FILE *fp = stdin; /* stream from which to determine sizes */
RuleCount count; /* rule_count() processing results */
int ch;
#if defined(MKIOCCCENTRY_USE)
/* IOCCC requires use of C locale */
set_ioccc_locale();
#endif /* MKIOCCCENTRY_USE */
while ((ch = getopt(argc, argv, "6ihv:aV")) != -1) {
switch (ch) {
case 'i': /* ignored for backward compatibility */
break;
case 'v':
errno = 0;
verbosity_level = (int)strtol(optarg, NULL, 0);
if (errno != 0) {
iocccsize_errx(4, "cannot parse -v arg: %s", optarg);
not_reached();
}
break;
case 'q':
msg_warn_silent = true;
break;
case 'V':
printf("%s\n", iocccsize_version);
exit(3); /*ooo*/
case '6': /* You're a RTFS master! Congrats. */
iocccsize_errx(6, "There is NO... Rule 6! I'm not a number! I'm a free(void *man)!"); /*ooo*/
not_reached();
case 'h':
fprintf(stderr, "%s%s", usage0, usage1);
fprintf(stderr, "\niocccsize version: %s\n", iocccsize_version);
exit(2); /*ooo*/
break;
default:
fprintf(stderr, "unknown -option\n");
fprintf(stderr, "%s%s", usage0, usage1);
exit(4); /*ooo*/
break;
}
}
if (optind + 1 == argc) {
/* Redirect stdin to file path argument. */
errno = 0;
fp = fopen(argv[optind], "r");
if (fp == NULL) {
iocccsize_errx(6, "fopen(%s) failed", argv[optind]); /*ooo*/
not_reached();
}
} else if (optind != argc) {
/* Too many arguments. */
fprintf(stderr, "%s%s", usage0, usage1);
exit(4); /*ooo*/
not_reached();
}
(void) setvbuf(fp, NULL, _IOLBF, 0);
/* The Count - 1 Muha .. 2 Muhaha .. 3 Muhahaha ... */
count = rule_count(fp);
if (verbosity_level == 0) {
(void) printf("%ju\n", (uintmax_t)count.rule_2b_size);
} else {
(void) printf("%ju %ju %ju\n", (uintmax_t)count.rule_2b_size, (uintmax_t)count.rule_2a_size,
(uintmax_t)count.keywords);
}
/*
* issue warnings
*/
if (1 < verbosity_level && 0 < count.char_warning) {
iocccsize_warnx("Warning: character(s) with high bit set found! Be careful you don't violate rule 13!");
}
if (1 < verbosity_level && count.nul_warning) {
iocccsize_warnx("Warning: NUL character(s) found! Be careful you don't violate rule 13!");
}
if (count.trigraph_warning) {
iocccsize_warnx("Warning: unknown or invalid trigraph(s) found! Is that a bug in, or a feature of your code?");
}
if (1 < verbosity_level && 0 < count.wordbuf_warning) {
iocccsize_warnx("Warning: word buffer overflow! Is that a bug in, or a feature of your code?");
}
if (count.ungetc_warning) {
iocccsize_warnx("Warning: ungetc error: @SirWumpus goofed. The count on stdout may be invalid under rule 2!");
}
if (count.rule_2a_size > RULE_2A_SIZE) {
iocccsize_warnx("Warning: your source under Rule 2a: %ju exceeds Rule 2a limit: %ju: Rule 2a violation!\n",
(uintmax_t)count.rule_2a_size, (uintmax_t)RULE_2A_SIZE);
}
if (count.rule_2b_size > RULE_2B_SIZE) {
iocccsize_warnx("Warning: your source under Rule 2b: %ju exceeds Rule 2b limit: %ju: Rule 2b violation!\n",
(uintmax_t)count.rule_2b_size, (uintmax_t)RULE_2B_SIZE);
}
/*
* All Done!!! All Done!!! -- Jessica Noll, Age 2
*/
if ((count.rule_2a_size > RULE_2A_SIZE) || (count.rule_2b_size > RULE_2B_SIZE)) {
exit(1); /*ooo*/
}
exit(0); /*ooo*/
}