OSDN Git Service

Small fix.
[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 <sys/stat.h>
34 #include <signal.h>
35
36 /*Hash size*/
37 #ifdef __cplusplus
38 #define MY_HASH_LENGTH mhash_384::MHash384::HASH_LEN
39 #else
40 #define MY_HASH_LENGTH MHASH_384_LEN
41 #endif
42
43 /*Parameters*/
44 typedef struct param_t
45 {
46         const CHAR *filename;
47         int enable_bench;
48         int show_progress;
49         int test_mode;
50         int use_upper_case;
51         int curly_brackets;
52         int raw_output;
53 }
54 param_t;
55
56 /*Version*/
57 typedef struct version_t
58 {
59         uint_fast16_t major;
60         uint_fast16_t minor;
61         uint_fast16_t patch;
62 }
63 version_t;
64
65 /*Get version*/
66 static version_t get_version(void)
67 {
68         version_t version_info;
69 #ifdef __cplusplus
70         mhash_384::MHash384::version(version_info.major, version_info.minor, version_info.patch);
71 #else
72         version_info.major = MHASH_384_VERSION_MAJOR;
73         version_info.minor = MHASH_384_VERSION_MINOR;
74         version_info.patch = MHASH_384_VERSION_PATCH;
75 #endif
76         return version_info;
77 }
78
79 /*The logo*/
80 static void print_logo(void)
81 {
82         const version_t version = get_version();
83         fprintf(stderr, "\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, __DATE__);
84         fprintf(stderr, "Copyright(c) 2016-2018 LoRd_MuldeR <mulder2@gmx.de>, released under the MIT License.\n\n");
85 }
86
87 /*File name suffix*/
88 #ifdef _WIN32
89 #define EXE_SUFFIX ".exe"
90 #else
91 #define EXE_SUFFIX ""
92 #endif
93
94 /*Print help screen*/
95 static void print_help(void)
96 {
97         fprintf(stderr, "Built with " COMPILER_TYPE " v%u.%u.%u on " SYSTEM_TYPE " [" COMPILER_ARCH "]\n\n", COMPILER_VERS_MAJOR, COMPILER_VERS_MINOR, COMPILER_VERS_PATCH);
98         fprintf(stderr, "Usage:\n");
99         fprintf(stderr, "  mhash384" EXE_SUFFIX " [options] [input_file]\n\n");
100         fprintf(stderr, "Options:\n");
101         fprintf(stderr, "  -p, --progress  show progress while processing\n");
102         fprintf(stderr, "  -u, --upper     print digest in upper case letters\n");
103         fprintf(stderr, "  -c, --curly     print digest using C-style curly brackets\n");
104         fprintf(stderr, "  -r, --raw       output \"raw\" bytes (no \"hex\" encoding)\n");
105         fprintf(stderr, "  -b, --bench     compute and print throughput\n");
106         fprintf(stderr, "  -v, --version   print the version string and exit\n");
107         fprintf(stderr, "  -t, --test      execute self-test and exit\n");
108         fprintf(stderr, "  -h, --help      print this help screen and exit\n\n");
109         fprintf(stderr, "If no input file is specified, input will be read from STDIN.\n\n");
110 }
111
112 /*Parse arguments*/
113 static int parse_arguments(param_t *param, int argc, CHAR *argv[])
114 {
115         int i, stop = 0;
116         memset(param, 0, sizeof(param_t));
117         for (i = 1; i < argc; ++i)
118         {
119                 if (!stop)
120                 {
121                         if (!STRICMP(argv[i], T("--")))
122                         {
123                                 stop = 1;
124                                 continue;
125                         }
126                         else if (!STRICMP(argv[i], T("-b")) || !STRICMP(argv[i], T("--bench")))
127                         {
128                                 param->enable_bench = 1;
129                                 continue;
130                         }
131                         else if (!STRICMP(argv[i], T("-t")) || !STRICMP(argv[i], T("--test")))
132                         {
133                                 param->test_mode = 1;
134                                 continue;
135                         }
136                         else if (!STRICMP(argv[i], T("-p")) || !STRICMP(argv[i], T("--progress")))
137                         {
138                                 param->show_progress = 1;
139                                 continue;
140                         }
141                         else if (!STRICMP(argv[i], T("-u")) || !STRICMP(argv[i], T("--upper")))
142                         {
143                                 param->use_upper_case = 1;
144                                 continue;
145                         }
146                         else if (!STRICMP(argv[i], T("-c")) || !STRICMP(argv[i], T("--curly")))
147                         {
148                                 param->curly_brackets = 1;
149                                 continue;
150                         }
151                         else if (!STRICMP(argv[i], T("-r")) || !STRICMP(argv[i], T("--raw")))
152                         {
153                                 param->raw_output = 1;
154                                 continue;
155                         }
156                         else if (!STRICMP(argv[i], T("-h")) || !STRICMP(argv[i], T("--help")) || !STRICMP(argv[i], T("/?")))
157                         {
158                                 print_logo();
159                                 print_help();
160                                 return 0;
161                         }
162                         else if (!STRICMP(argv[i], T("-v")) || !STRICMP(argv[i], T("--version")))
163                         {
164                                 const version_t version = get_version();
165                                 printf("mhash-384 version %u.%u.%u (built %s)\n", (unsigned int)version.major, (unsigned int)version.minor, (unsigned int)version.patch, __DATE__);
166                                 return 0;
167                         }
168                         else if ((argv[i][0] == T('-')) && (argv[i][1] != T('\0')))
169                         {
170                                 print_logo();
171                                 fprintf(stderr, "Unknown option:\n" FMT_S "\n\n", argv[i]);
172                                 return 0;
173                         }
174                 }
175                 if (!param->filename)
176                 {
177                         param->filename = argv[i];
178                 }
179                 else
180                 {
181                         print_logo();
182                         fprintf(stderr, "Excess argument:\n" FMT_S "\n\n", argv[i]);
183                         return 0;
184                 }
185         }
186         if (param->filename && (!STRICMP(param->filename, T("-"))) && (!stop))
187         {
188                 param->filename = NULL;
189         }
190         if (param->raw_output)
191         {
192                 if (param->use_upper_case)
193                 {
194                         fprintf(stderr, "Error: Options \"-u\" and \"-r\" are mutually exclusive!\n\n");
195                         return 0;
196                 }
197                 if (param->curly_brackets)
198                 {
199                         fprintf(stderr, "Error: Options \"-c\" and \"-r\" are mutually exclusive!\n\n");
200                         return 0;
201                 }
202         }
203         return 1;
204 }
205
206 /*file size*/
207 static uint64_t get_file_size(FILE *const file)
208 {
209         struct stat64 info;
210         if (fstat64(fileno(file), &info) || ((info.st_mode & S_IFMT) != S_IFREG))
211         {
212                 return 0;
213         }
214         return (uint64_t) info.st_size;
215 }
216
217 /*progress*/
218 static void print_progress(const uint64_t size_total, const uint64_t size_processed)
219 {
220         if (size_total)
221         {
222                 fprintf(stderr, "\r%.1f%% of %" PRIu64 " bytes processed...", ((double)size_processed) / ((double)size_total) * 100.0, size_total);
223         }
224         else
225         {
226                 fprintf(stderr, "\r%" PRIu64 " bytes processed...", size_processed);
227         }
228 }
229
230 /*print digest*/
231 #define _PUT_HEX_CHAR(X,Y,Z) putchar(X[((Y) >> (Z)) & 0xFU])
232 static void print_digest(const uint8_t *const digest, const int uppercase, const int curly)
233 {
234         static const char *const HEX_UPR = "0123456789ABCDEF";
235         static const char *const HEX_LWR = "0123456789abcdef";
236         const char *const hex = uppercase ? HEX_UPR : HEX_LWR;
237         uint16_t count;
238         if (curly)
239         {
240                 fputs("{ ", stdout);
241         }
242         for (count = 0U; count < MY_HASH_LENGTH; ++count)
243         {
244                 if (curly)
245                 {
246                         fputs(count ? ", 0x" : "0x", stdout);
247                 }
248                 _PUT_HEX_CHAR(hex, digest[count], 4);
249                 _PUT_HEX_CHAR(hex, digest[count], 0);
250         }
251         if (curly)
252         {
253                 fputs(" }", stdout);
254         }
255         putchar('\n');
256 }
257
258 /*sigint handler*/
259 static volatile int g_interrupted = 0;
260 static void sigint_handler(int sig_no)
261 {
262         g_interrupted = 1;
263         signal(sig_no, sigint_handler);
264         fclose(stdin);
265 }
266
267 #endif /*MHASH_CLI_UTILS_INCLUDED*/