OSDN Git Service

65e0d3b710d206310f175be34dccf05056ef09b9
[mhash384/mhash384.git] / src / utilities.h
1 /* ---------------------------------------------------------------------------------------------- */
2 /* MHash-384 - Example application (utility functions)                                            */
3 /* Copyright(c) 2016-2018 LoRd_MuldeR <mulder2@gmx.de>                                            */
4 /*                                                                                                */
5 /* Permission is hereby granted, free of charge, to any person obtaining a copy of this software  */
6 /* and associated documentation files (the "Software"), to deal in the Software without           */
7 /* restriction, including without limitation the rights to use, copy, modify, merge, publish,     */
8 /* distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the  */
9 /* Software is furnished to do so, subject to the following conditions:                           */
10 /*                                                                                                */
11 /* The above copyright notice and this permission notice shall be included in all copies or       */
12 /* substantial portions of the Software.                                                          */
13 /*                                                                                                */
14 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING  */
15 /* BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND     */
16 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   */
17 /* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, */
18 /* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.        */
19 /* ---------------------------------------------------------------------------------------------- */
20
21 #ifndef MHASH_CLI_UTILS_INCLUDED
22 #define MHASH_CLI_UTILS_INCLUDED
23
24 /*Enable large files*/
25 #define __USE_LARGEFILE64 1
26
27 /*Includes*/
28 #include "compat.h"
29 #include "sysinfo.h"
30
31 /*CRT includes*/
32 #include <stdio.h>
33 #include <string.h>
34 #include <sys/stat.h>
35 #include <signal.h>
36 #include <ctype.h>
37 #include <errno.h>
38 #include <fcntl.h>
39
40 /*Win32-only header*/
41 #ifdef _WIN32
42 #include <io.h>
43 #endif
44
45 /*Hash size*/
46 #ifdef __cplusplus
47 #define MY_HASH_LENGTH mhash_384::MHash384::HASH_LEN
48 #else
49 #define MY_HASH_LENGTH MHASH_384_LEN
50 #endif
51
52 /*Build date*/
53 static const CHAR *const BUILD_DATE = T(__DATE__);
54
55 /*Mode*/
56 #define OPMODE_HELP 1
57 #define OPMODE_VERS 2
58 #define OPMODE_TEST 3
59
60 /*Parameters*/
61 typedef struct param_t
62 {
63         int opmode;
64         int enable_bench;
65         int show_progress;
66         int use_upper_case;
67         int curly_brackets;
68         int raw_output;
69 }
70 param_t;
71
72 /*Version*/
73 typedef struct version_t
74 {
75         uint_fast16_t major;
76         uint_fast16_t minor;
77         uint_fast16_t patch;
78 }
79 version_t;
80
81 /*Get version*/
82 static version_t get_version(void)
83 {
84         version_t version_info;
85 #ifdef __cplusplus
86         mhash_384::MHash384::version(version_info.major, version_info.minor, version_info.patch);
87 #else
88         version_info.major = MHASH_384_VERSION_MAJOR;
89         version_info.minor = MHASH_384_VERSION_MINOR;
90         version_info.patch = MHASH_384_VERSION_PATCH;
91 #endif
92         return version_info;
93 }
94
95 /*The logo*/
96 static void print_logo(void)
97 {
98         const version_t version = get_version();
99         FPRINTF(stderr, T("\nMHash384 v%u.%u.%u, simple fast portable header-only hashing library [%s]\n"), (unsigned int)version.major, (unsigned int)version.minor, (unsigned int)version.patch, BUILD_DATE);
100         FPRINTF(stderr, T("Copyright(c) 2016-%s LoRd_MuldeR <mulder2@gmx.de>, released under the MIT License.\n\n"), &BUILD_DATE[7]);
101 }
102
103 /*Lib version*/
104 static void print_vers(void)
105 {
106         const version_t version = get_version();
107         FPRINTF(stdout, T("mhash-384 version %u.%u.%u (built %s)\n"), (unsigned int)version.major, (unsigned int)version.minor, (unsigned int)version.patch, BUILD_DATE);
108 }
109
110 /*File name suffix*/
111 #ifdef _WIN32
112 #define EXE_SUFFIX ".exe"
113 #else
114 #define EXE_SUFFIX ""
115 #endif
116
117 /*Print help screen*/
118 static void print_help(void)
119 {
120         print_logo();
121         FPRINTF(stderr, T("Built with %s v%u.%u.%u on %s [%s]\n\n"), T(COMPILER_TYPE), COMPILER_VERS_MAJOR, COMPILER_VERS_MINOR, COMPILER_VERS_PATCH, T(SYSTEM_TYPE), T(COMPILER_ARCH));
122         FPUTS(T("Usage:\n"), stderr);
123         FPRINTF(stderr, T("  mhash384%s [options] [input_file]...\n\n"), T(EXE_SUFFIX));
124         FPUTS(T("Options:\n"), stderr);
125         FPUTS(T("  -p, --progress  show progress while processing\n"), stderr);
126         FPUTS(T("  -u, --upper     print digest in upper case letters\n"), stderr);
127         FPUTS(T("  -c, --curly     print digest using C-style curly brackets\n"), stderr);
128         FPUTS(T("  -r, --raw       output \"raw\" bytes (no \"hex\" encoding)\n"), stderr);
129         FPUTS(T("  -b, --bench     compute and print throughput\n"), stderr);
130         FPUTS(T("  -v, --version   print the version string and exit\n"), stderr);
131         FPUTS(T("  -t, --test      execute self-test and exit\n"), stderr);
132         FPUTS(T("  -h, --help      print this help screen and exit\n\n"), stderr);
133         FPUTS(T("If no input file is specified, input will be read from STDIN.\n\n"), stderr);
134 }
135
136 /*Check specific option*/
137 #define IS_OPTION(ARGV, IS_LONG, NAME_SHRT, NAME_LONG) \
138         ((IS_LONG) ? (!STRICMP((ARGV), (NAME_LONG))) : (TOLOWER(*(ARGV)) == (NAME_SHRT)))
139
140 /*Parse option*/
141 static int parse_option(param_t *param, const CHAR *const argv, const int is_long)
142 {
143         if (IS_OPTION(argv, is_long, T('b'), T("bench")))
144         {
145                 param->enable_bench = 1;
146                 return 1;
147         }
148         if (IS_OPTION(argv, is_long, T('p'), T("progress")))
149         {
150                 param->show_progress = 1;
151                 return 1;
152         }
153         if (IS_OPTION(argv, is_long, T('u'), T("upper")))
154         {
155                 param->use_upper_case = 1;
156                 return 1;
157         }
158         if (IS_OPTION(argv, is_long, T('c'), T("curly")))
159         {
160                 param->curly_brackets = 1;
161                 return 1;
162         }
163         if (IS_OPTION(argv, is_long, T('r'), T("raw")))
164         {
165                 param->raw_output = 1;
166                 return 1;
167         }
168         if (IS_OPTION(argv, is_long, T('h'), T("help")))
169         {
170                 param->opmode = OPMODE_HELP;
171                 return 1;
172         }
173         if (IS_OPTION(argv, is_long, T('v'), T("version")))
174         {
175                 param->opmode = OPMODE_VERS;
176                 return 1;
177         }
178         if (IS_OPTION(argv, is_long, T('t'), T("test")))
179         {
180                 param->opmode = OPMODE_TEST;
181                 return 1;
182         }
183         return 0;
184 }
185
186 /*Parse arguments*/
187 static int parse_arguments(param_t *const param, int argc, CHAR *argv[])
188 {
189         int i, j;
190         memset(param, 0, sizeof(param_t));
191         for (i = 1; i < argc; ++i)
192         {
193                 if (argv[i][0] == T('-'))
194                 {
195                         if (argv[i][1] == T('-'))
196                         {
197                                 if (!argv[i][2])
198                                 {
199                                         ++i;
200                                         break; /*stop*/
201                                 }
202                                 if (!parse_option(param, &argv[i][2], 1))
203                                 {
204                                         print_logo();
205                                         FPRINTF(stderr, T("Unknown option:\n%s\n\n"), argv[i]);
206                                         return 0;
207                                 }
208                                 continue;
209                         }
210                         else if (argv[i][1])
211                         {
212                                 for (j = 1; argv[i][j]; ++j)
213                                 {
214                                         if(!parse_option(param, &argv[i][j], 0))
215                                         {
216                                                 print_logo();
217                                                 FPRINTF(stderr, T("Unknown option(s):\n%s\n\n"), argv[i]);
218                                                 return 0;
219                                         }
220                                 }
221                                 continue;
222                         }
223                 }
224                 break; /*no more options*/
225         }
226         if (param->raw_output && (param->use_upper_case || param->curly_brackets))
227         {
228                 print_logo();
229                 FPRINTF(stderr, T("Error: Options \"-%c\" and \"-r\" are mutually exclusive!\n\n"), param->use_upper_case ? T('u') : T('c'));
230                 return 0;
231         }
232         return i;
233 }
234
235 /*is file readable?*/
236 static int is_file_readable(const CHAR *const filename)
237 {
238         struct stat64 info;
239         if (!STAT64(filename, &info))
240         {
241                 if ((info.st_mode & S_IFMT) == S_IFDIR)
242                 {
243                         errno = EISDIR;
244                         return 0;
245                 }
246         }
247         return (!ACCESS(filename, R_OK));
248 }
249
250 /*file size*/
251 static uint64_t get_file_size(FILE *const file)
252 {
253         struct stat64 info;
254         if (fstat64(FILENO(file), &info) || ((info.st_mode & S_IFMT) != S_IFREG))
255         {
256                 return 0;
257         }
258         return (uint64_t) info.st_size;
259 }
260
261 /*progress*/
262 static void print_progress(const uint64_t size_total, const uint64_t size_processed)
263 {
264         if (size_total)
265         {
266                 FPRINTF(stderr, T("\r%.1f%% of %") T(PRIu64) T(" bytes processed..."), ((double)size_processed) / ((double)size_total) * 100.0, size_total);
267         }
268         else
269         {
270                 FPRINTF(stderr, T("\r%") T(PRIu64) T(" bytes processed..."), size_processed);
271         }
272 }
273
274 /*print digest*/
275 #define _PUT_HEX_CHAR(W,X,Y,Z) FPUTC(W[((X) >> (Y)) & 0xFU], (Z))
276 static void print_digest(FILE *const stream, const uint8_t *const digest, const int uppercase, const int curly)
277 {
278         static const CHAR *const HEX_UPR = T("0123456789ABCDEF");
279         static const CHAR *const HEX_LWR = T("0123456789abcdef");
280         const CHAR *const hex = uppercase ? HEX_UPR : HEX_LWR;
281         uint16_t count;
282         if (curly)
283         {
284                 FPUTS(T("{ "), stream);
285         }
286         for (count = 0U; count < MY_HASH_LENGTH; ++count)
287         {
288                 if (curly)
289                 {
290                         FPUTS(count ? T(", 0x") : T("0x"), stream);
291                 }
292                 _PUT_HEX_CHAR(hex, digest[count], 4, stream);
293                 _PUT_HEX_CHAR(hex, digest[count], 0, stream);
294         }
295         if (curly)
296         {
297                 FPUTS(T(" }"), stream);
298         }
299 }
300
301 /*sigint handler*/
302 static volatile int g_interrupted;
303 static void sigint_handler(int sig_no)
304 {
305         g_interrupted = 1;
306         signal(sig_no, sigint_handler);
307         fclose(stdin);
308 }
309
310 #endif /*MHASH_CLI_UTILS_INCLUDED*/