1 /* vim: set ts=8 sts=4 sw=4 tw=80 noet: */
2 /*======================================================================
3 Copyright (C) 2004,2005,2009,2013 Walter Doekes <walter+tthsum@wjd.nu>
4 This file is part of tthsum.
5 
6 tthsum is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10 
11 tthsum is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 GNU General Public License for more details.
15 
16 You should have received a copy of the GNU General Public License
17 along with tthsum.  If not, see <http://www.gnu.org/licenses/>.
18 ======================================================================*/
19 #include "texts.h"
20 
21 #include <assert.h>
22 
23 #ifdef _WIN32
24 #    define WINDOWS_LEAN_AND_MEAN
25 #    include <windows.h>
26 #else /* !_WIN32 */
27 #    include <stdio.h>
28 #    include <string.h>
29 #    include <errno.h>
30 #endif /* !_WIN32 */
31 
32 
33 static int last_error = 0;
34 static int last_error_os = 0;
35 static const char* last_error_context = 0;
36 #define LAST_ERROR_SIZE 512
37 static char last_error_buf[LAST_ERROR_SIZE];
38 
39 static const char* texts[] = {
40     /* ERROR_FIRST */
41     "No error yet",
42     /* BASE32_INVALID_CHARACTER */
43     "Invalid character encountered in BASE32 stream",
44     /* ESCAPE_INVALID_ESCAPE */
45     "Invalid escape sequence encountered",
46     /* TEXTS_UNKNOWN_ERROR */
47     "Unknown error",
48     /* THEX_INVALID_BLOCK_SIZE */
49     "The read operation isn't supplying multiples of 1024",
50     /* TTHSUM_FILENAME_TOO_LARGE */
51     "File name is too long",
52     /* TTHSUM_LINE_CORRUPT */
53     "Improperly formatted line",
54     /* TTHSUM_MISMATCHED_TTH */
55     "TTH check failed for",
56     /* UTF8_INVALID_UNICODE */
57     "Invalid character encountered in UNICODE stream",
58     /* UTF8_INVALID_UTF8 */
59     "Invalid character encountered in UTF8 stream",
60     /* UTF8_OVERLONG_UTF8 */
61     "Overlong character encountered in UTF8 stream"
62     /* ERROR_LAST */
63 };
64 
set_error(const char * context,int error)65 void set_error(const char* context, int error) {
66     assert(strlen(context) < 32);
67     if (error == -1) {
68 #ifdef _WIN32
69 	last_error = GetLastError();
70 #else /* !_WIN32 */
71 	last_error = errno;
72 #endif /* !_WIN32 */
73 	last_error_os = 1;
74     } else {
75 	last_error = error;
76 	last_error_os = 0;
77     }
78     last_error_context = context;
79 }
80 
my_strcpy(char * dst,const char * src,int size)81 static int my_strcpy(char* dst, const char* src, int size) {
82     char *d = dst;
83 
84     if (size <= 0)
85         return 0; /* no warning when truncating */
86 
87     while (--size != 0 && *src != '\0') {
88 	*d++ = *src++;
89     }
90     *d = '\0';
91 
92     return d - dst; /* how many bytes we wrote excluding NUL */
93 }
94 
get_error()95 const char* get_error() {
96     int i;
97 #ifdef _WIN32
98     DWORD w;
99 #endif /* !_WIN32 */
100 
101     /* Avoid snprintf because it's not C90 */
102     if (!last_error_os) {
103 	i = my_strcpy(last_error_buf, last_error_context, LAST_ERROR_SIZE);
104 	i += my_strcpy(last_error_buf + i, ": ", LAST_ERROR_SIZE - i);
105 	my_strcpy(last_error_buf + i, texts[last_error], LAST_ERROR_SIZE - i);
106 	return last_error_buf;
107     }
108 
109     i = my_strcpy(last_error_buf, last_error_context, LAST_ERROR_SIZE);
110     i += my_strcpy(last_error_buf + i, ": ", LAST_ERROR_SIZE - i);
111 #ifdef _WIN32
112     if ((w = FormatMessage(
113 	    FORMAT_MESSAGE_IGNORE_INSERTS | FORMAT_MESSAGE_FROM_SYSTEM,
114 	    NULL, (DWORD)last_error, 0, last_error_buf + i,
115 	    LAST_ERROR_SIZE - 32 - i, NULL)) != 0) {
116 	if (w >= 2) /* 32 is more than enough for " (0xINT)" */
117 	    sprintf(last_error_buf + i + w - 2, " (0x%x)", last_error);
118     } else {
119 	i += my_strcpy(last_error_buf + i, get_text(TEXTS_UNKNOWN_ERROR),
120 		LAST_ERROR_SIZE - i);
121 	if (LAST_ERROR_SIZE - i >= 32) {
122 	    sprintf(last_error_buf + i, " (0x%x)", (unsigned)last_error);
123 	}
124     }
125 #else /* !_WIN32 */
126     i += my_strcpy(last_error_buf + i, strerror(last_error),
127 	    LAST_ERROR_SIZE - i);
128     if (LAST_ERROR_SIZE - i >= 32) { /* 32 is more than enough */
129 	sprintf(last_error_buf + i, " (%i)", last_error);
130     }
131 #endif /* !_WIN32 */
132     return last_error_buf;
133 }
134 
get_text(enum text_id id)135 const char* get_text(enum text_id id) {
136     return texts[id];
137 }
138