2 * edit.c edit string to ascii, and ascii to internal
4 * Kern Sibbald, December MMII
10 Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
12 This program is free software; you can redistribute it and/or
13 modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation; either version 2 of
15 the License, or (at your option) any later version.
17 This program is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 General Public License for more details.
22 You should have received a copy of the GNU General Public
23 License along with this program; if not, write to the Free
24 Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
32 /* We assume ASCII input and don't worry about overflow */
33 uint64_t str_to_uint64(char *str)
35 register char *p = str;
36 register uint64_t value = 0;
38 while (B_ISSPACE(*p)) {
44 while (B_ISDIGIT(*p)) {
45 value = value * 10 + *p - '0';
51 int64_t str_to_int64(char *str)
53 register char *p = str;
54 register int64_t value;
57 while (B_ISSPACE(*p)) {
62 } else if (*p == '-') {
66 value = str_to_uint64(p);
76 * Edit an integer number with commas, the supplied buffer
77 * must be at least 27 bytes long. The incoming number
78 * is always widened to 64 bits.
80 char *edit_uint64_with_commas(uint64_t val, char *buf)
82 sprintf(buf, "%" lld, val);
83 return add_commas(buf, buf);
87 * Edit an integer number, the supplied buffer
88 * must be at least 27 bytes long. The incoming number
89 * is always widened to 64 bits.
91 char *edit_uint64(uint64_t val, char *buf)
93 sprintf(buf, "%" lld, val);
99 * Convert a string duration to utime_t (64 bit seconds)
100 * Returns 0: if error
101 1: if OK, and value stored in value
103 int duration_to_utime(char *str, utime_t *value)
108 * The "n" = mins and months appears before minutes so that m maps
109 * to months. These "kludges" make it compatible with pre 1.31
112 static const char *mod[] = {"n", "seconds", "months", "minutes",
113 "hours", "days", "weeks", "quarters", "years", NULL};
114 static const int32_t mult[] = {60, 1, 60*60*24*30, 60,
115 60*60, 60*60*24, 60*60*24*7, 60*60*24*91, 60*60*24*365};
120 * Look for modifier by walking back looking for the first
123 strip_trailing_junk(str);
125 /* Strip trailing spaces */
126 for (i=len; i>0; i--) {
127 if (!B_ISSPACE(str[i-1])) {
132 /* Find beginning of the modifier */
134 if (!B_ISALPHA(str[i-1])) {
138 /* If not found, error */
139 if (i == 0 || i == len) {
140 Dmsg2(200, "error i=%d len=%d\n", i, len);
143 /* Move modifier to mod_str */
144 bstrncpy(mod_str, &str[i], sizeof(mod_str));
145 mod_len = strlen(mod_str);
146 if (mod_len == 0) { /* Make sure we have a modifier */
147 Dmsg0(200, "No modifier found\n");
150 Dmsg2(200, "in=%s mod=%s:\n", str, mod_str);
151 /* Backup over any spaces in front of modifier */
153 if (B_ISSPACE(str[i-1])) {
159 /* The remainder (beginning) should be our number */
160 if (!is_a_number(str)) {
161 Dmsg0(200, "input not a number\n");
164 /* Now find the multiplier corresponding to the modifier */
165 for (i=0; mod[i]; i++) {
166 if (strncasecmp(mod_str, mod[i], mod_len) == 0) {
170 if (mod[i] == NULL) {
171 Dmsg0(200, "Modifier not found\n");
172 return 0; /* modifer not found */
174 Dmsg2(200, "str=%s: mult=%d\n", str, mult[i]);
176 val = strtod(str, NULL);
177 if (errno != 0 || val < 0) {
180 *value = (utime_t)(val * mult[i]);
186 * Edit a utime "duration" into ASCII
188 char *edit_utime(utime_t val, char *buf)
191 static int mult[] = {60*60*24*365, 60*60*24*30, 60*60*24, 60*60, 60};
192 static char *mod[] = {"year", "month", "day", "hour", "min"};
197 for (i=0; i<5; i++) {
198 times = val / mult[i];
200 val = val - (utime_t)times * mult[i];
201 sprintf(mybuf, "%d %s%s ", times, mod[i], times>1?"s":"");
205 if (val == 0 && strlen(buf) == 0) {
206 strcat(buf, "0 secs");
207 } else if (val != 0) {
208 sprintf(mybuf, "%d sec%s", (uint32_t)val, val>1?"s":"");
215 * Convert a size size in bytes to uint64_t
216 * Returns 0: if error
217 1: if OK, and value stored in value
219 int size_to_uint64(char *str, int str_len, uint64_t *rtn_value)
223 int mod[] = {'*', 'k', 'm', 'g', 0}; /* first item * not used */
224 uint64_t mult[] = {1, /* byte */
226 1048576, /* megabyte */
227 1073741824}; /* gigabyte */
229 #ifdef we_have_a_compiler_that_works
230 int mod[] = {'*', 'k', 'm', 'g', 't', 0};
231 uint64_t mult[] = {1, /* byte */
233 1048576, /* megabyte */
234 1073741824, /* gigabyte */
235 1099511627776};/* terabyte */
238 Dmsg1(400, "Enter sized to uint64 str=%s\n", str);
240 /* Look for modifier */
241 ch = str[str_len - 1];
247 while (mod[++i] != 0) {
250 str[str_len] = 0; /* strip modifier */
255 if (mod[i] == 0 || !is_a_number(str)) {
258 Dmsg3(400, "size str=:%s: %lf i=%d\n", str, strtod(str, NULL), i);
261 value = strtod(str, NULL);
262 if (errno != 0 || value < 0) {
265 #if defined(HAVE_WIN32)
266 /* work around microsofts non handling of uint64 to double cvt*/
267 *rtn_value = (uint64_t)(value * (__int64)mult[i]);
268 Dmsg2(400, "Full value = %lf %" lld "\n", value * (__int64)mult[i],
269 (uint64_t)(value * (__int64)mult[i]));
271 *rtn_value = (uint64_t)(value * mult[i]);
272 Dmsg2(400, "Full value = %lf %" lld "\n", value * mult[i],
273 (uint64_t)(value * mult[i]));
279 * Check if specified string is a number or not.
280 * Taken from SQLite, cool, thanks.
282 int is_a_number(const char *n)
284 bool digit_seen = false;
286 if( *n == '-' || *n == '+' ) {
289 while (B_ISDIGIT(*n)) {
293 if (digit_seen && *n == '.') {
295 while (B_ISDIGIT(*n)) { n++; }
297 if (digit_seen && (*n == 'e' || *n == 'E')
298 && (B_ISDIGIT(n[1]) || ((n[1]=='-' || n[1] == '+') && B_ISDIGIT(n[2])))) {
299 n += 2; /* skip e- or e+ or e digit */
300 while (B_ISDIGIT(*n)) { n++; }
302 return digit_seen && *n==0;
306 * Check if the specified string is an integer
308 int is_an_integer(const char *n)
310 bool digit_seen = false;
311 while (B_ISDIGIT(*n)) {
315 return digit_seen && *n==0;
319 * Check if Bacula Resoure Name is valid
322 * Check if the Volume name has legal characters
323 * If ua is non-NULL send the message
325 bool is_name_valid(char *name, POOLMEM **msg)
329 /* Special characters to accept */
330 const char *accept = ":.-_ ";
332 /* Restrict the characters permitted in the Volume name */
333 for (p=name; *p; p++) {
334 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
338 Mmsg(msg, _("Illegal character \"%c\" in name.\n"), *p);
343 if (len >= MAX_NAME_LENGTH) {
345 Mmsg(msg, _("Name too long.\n"));
351 Mmsg(msg, _("Volume name must be at least one character long.\n"));
361 * Add commas to a string, which is presumably
364 char *add_commas(char *val, char *buf)
382 for (i=0; i < 3; i++) {
391 void d_msg(char*, int, int, char*, ...)
393 int main(int argc, char *argv[])
395 char *str[] = {"3", "3n", "3 hours", "3.5 day", "3 week", "3 m", "3 q", "3 years"};
400 for (int i=0; i<8; i++) {
402 if (!duration_to_utime(buf, &val)) {
403 printf("Error return from duration_to_utime for in=%s\n", str[i]);
406 edit_utime(val, outval);
407 printf("in=%s val=%lld outval=%s\n", str[i], val, outval);