]> icculus.org git repositories - icculus/xz.git/blob - src/lzma/util.c
Oh well, big messy commit again. Some highlights:
[icculus/xz.git] / src / lzma / util.c
1 ///////////////////////////////////////////////////////////////////////////////
2 //
3 /// \file       util.c
4 /// \brief      Miscellaneous utility functions
5 //
6 //  Copyright (C) 2007 Lasse Collin
7 //
8 //  This program is free software; you can redistribute it and/or
9 //  modify it under the terms of the GNU Lesser General Public
10 //  License as published by the Free Software Foundation; either
11 //  version 2.1 of the License, or (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16 //  Lesser General Public License for more details.
17 //
18 ///////////////////////////////////////////////////////////////////////////////
19
20 #include "private.h"
21
22
23 extern void *
24 xrealloc(void *ptr, size_t size)
25 {
26         assert(size > 0);
27
28         ptr = realloc(ptr, size);
29         if (ptr == NULL)
30                 message_fatal("%s", strerror(errno));
31
32         return ptr;
33 }
34
35
36 extern char *
37 xstrdup(const char *src)
38 {
39         assert(src != NULL);
40         const size_t size = strlen(src) + 1;
41         char *dest = xmalloc(size);
42         return memcpy(dest, src, size);
43 }
44
45
46 extern uint64_t
47 str_to_uint64(const char *name, const char *value, uint64_t min, uint64_t max)
48 {
49         uint64_t result = 0;
50
51         // Skip blanks.
52         while (*value == ' ' || *value == '\t')
53                 ++value;
54
55         if (*value < '0' || *value > '9')
56                 message_fatal(_("%s: Value is not a non-negative "
57                                 "decimal integer"), value);
58
59         do {
60                 // Don't overflow.
61                 if (result > (UINT64_MAX - 9) / 10)
62                         goto error;
63
64                 result *= 10;
65                 result += *value - '0';
66                 ++value;
67         } while (*value >= '0' && *value <= '9');
68
69         if (*value != '\0') {
70                 // Look for suffix.
71                 static const struct {
72                         const char name[4];
73                         uint64_t multiplier;
74                 } suffixes[] = {
75                         { "k",   UINT64_C(1000) },
76                         { "kB",  UINT64_C(1000) },
77                         { "M",   UINT64_C(1000000) },
78                         { "MB",  UINT64_C(1000000) },
79                         { "G",   UINT64_C(1000000000) },
80                         { "GB",  UINT64_C(1000000000) },
81                         { "Ki",  UINT64_C(1024) },
82                         { "KiB", UINT64_C(1024) },
83                         { "Mi",  UINT64_C(1048576) },
84                         { "MiB", UINT64_C(1048576) },
85                         { "Gi",  UINT64_C(1073741824) },
86                         { "GiB", UINT64_C(1073741824) }
87                 };
88
89                 uint64_t multiplier = 0;
90                 for (size_t i = 0; i < ARRAY_SIZE(suffixes); ++i) {
91                         if (strcmp(value, suffixes[i].name) == 0) {
92                                 multiplier = suffixes[i].multiplier;
93                                 break;
94                         }
95                 }
96
97                 if (multiplier == 0) {
98                         message(V_ERROR, _("%s: Invalid multiplier suffix. "
99                                         "Valid suffixes:"), value);
100                         message_fatal("`k' (10^3), `M' (10^6), `G' (10^9) "
101                                         "`Ki' (2^10), `Mi' (2^20), "
102                                         "`Gi' (2^30)");
103                 }
104
105                 // Don't overflow here either.
106                 if (result > UINT64_MAX / multiplier)
107                         goto error;
108
109                 result *= multiplier;
110         }
111
112         if (result < min || result > max)
113                 goto error;
114
115         return result;
116
117 error:
118         message_fatal(_("Value of the option `%s' must be in the range "
119                                 "[%llu, %llu]"), name,
120                                 (unsigned long long)(min),
121                                 (unsigned long long)(max));
122 }
123
124
125 /*
126 /// \brief      Simple quoting to get rid of ASCII control characters
127 ///
128 /// This is not so cool and locale-dependent, but should be good enough
129 /// At least we don't print any control characters on the terminal.
130 ///
131 extern char *
132 str_quote(const char *str)
133 {
134         size_t dest_len = 0;
135         bool has_ctrl = false;
136
137         while (str[dest_len] != '\0')
138                 if (*(unsigned char *)(str + dest_len++) < 0x20)
139                         has_ctrl = true;
140
141         char *dest = malloc(dest_len + 1);
142         if (dest != NULL) {
143                 if (has_ctrl) {
144                         for (size_t i = 0; i < dest_len; ++i)
145                                 if (*(unsigned char *)(str + i) < 0x20)
146                                         dest[i] = '?';
147                                 else
148                                         dest[i] = str[i];
149
150                         dest[dest_len] = '\0';
151
152                 } else {
153                         // Usually there are no control characters,
154                         // so we can optimize.
155                         memcpy(dest, str, dest_len + 1);
156                 }
157         }
158
159         return dest;
160 }
161 */
162
163
164 extern bool
165 is_empty_filename(const char *filename)
166 {
167         if (filename[0] == '\0') {
168                 message_error(_("Empty filename, skipping"));
169                 return true;
170         }
171
172         return false;
173 }
174
175
176 extern bool
177 is_tty_stdin(void)
178 {
179         const bool ret = isatty(STDIN_FILENO);
180
181         if (ret)
182                 message_error(_("Compressed data not read from a terminal "
183                                 "unless `--force' is used."));
184
185         return ret;
186 }
187
188
189 extern bool
190 is_tty_stdout(void)
191 {
192         const bool ret = isatty(STDOUT_FILENO);
193
194         if (ret)
195                 message_error(_("Compressed data not written to a terminal "
196                                 "unless `--force' is used."));
197
198         return ret;
199 }