2 * edit.c edit string to ascii, and ascii to internal
4 * Kern Sibbald, December MMII
10 Copyright (C) 2000-2004 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;
41 while (B_ISSPACE(*p)) {
47 while (B_ISDIGIT(*p)) {
48 value = value * 10 + *p - '0';
54 int64_t str_to_int64(char *str)
56 register char *p = str;
57 register int64_t value;
58 bool negative = false;
63 while (B_ISSPACE(*p)) {
68 } else if (*p == '-') {
72 value = str_to_uint64(p);
81 * Edit an integer number with commas, the supplied buffer
82 * must be at least 27 bytes long. The incoming number
83 * is always widened to 64 bits.
85 char *edit_uint64_with_commas(uint64_t val, char *buf)
88 * Replacement for sprintf(buf, "%" llu, val)
91 mbuf[sizeof(mbuf)-1] = 0;
92 int i = sizeof(mbuf)-2; /* edit backward */
97 mbuf[i--] = "0123456789"[val%10];
101 strcpy(buf, &mbuf[i+1]);
102 return add_commas(buf, buf);
106 * Edit an integer number, the supplied buffer
107 * must be at least 27 bytes long. The incoming number
108 * is always widened to 64 bits.
110 char *edit_uint64(uint64_t val, char *buf)
113 * Replacement for sprintf(buf, "%" llu, val)
116 mbuf[sizeof(mbuf)-1] = 0;
117 int i = sizeof(mbuf)-2; /* edit backward */
122 mbuf[i--] = "0123456789"[val%10];
126 strcpy(buf, &mbuf[i+1]);
131 * Given a string "str", separate the integer part into
132 * str, and the modifier into mod.
134 static bool get_modifier(char *str, char *mod, int mod_len)
138 * Look for modifier by walking back looking for the first
141 strip_trailing_junk(str);
144 /* Find beginning of the modifier */
145 for (i=len; i > 0; i--) {
146 if (!B_ISALPHA(str[i-1])) {
151 /* If nothing found, error */
153 Dmsg2(900, "error i=%d len=%d\n", i, len);
157 /* Move modifier to its location */
158 bstrncpy(mod, &str[i], mod_len);
159 Dmsg2(900, "in=%s mod=%s:\n", str, mod);
161 /* Backup over any spaces in front of modifier */
162 for ( ; i > 0; i--) {
163 if (B_ISSPACE(str[i-1])) {
169 /* The remainder (beginning) should be our number */
170 if (!is_a_number(str)) {
171 Dmsg0(900, "input not a number\n");
178 * Convert a string duration to utime_t (64 bit seconds)
179 * Returns 0: if error
180 1: if OK, and value stored in value
182 int duration_to_utime(char *str, utime_t *value)
188 * The "n" = mins and months appears before minutes so that m maps
189 * to months. These "kludges" make it compatible with pre 1.31
192 static const char *mod[] = {"n", "seconds", "months", "minutes",
193 "hours", "days", "weeks", "quarters", "years", NULL};
194 static const int32_t mult[] = {60, 1, 60*60*24*30, 60,
195 60*60, 60*60*24, 60*60*24*7, 60*60*24*91, 60*60*24*365};
197 if (!get_modifier(str, mod_str, sizeof(mod_str))) {
200 /* Now find the multiplier corresponding to the modifier */
201 mod_len = strlen(mod_str);
202 for (i=0; mod[i]; i++) {
203 if (strncasecmp(mod_str, mod[i], mod_len) == 0) {
207 if (mod[i] == NULL) {
208 i = 1; /* no modifier, assume 1 */
210 Dmsg2(900, "str=%s: mult=%d\n", str, mult[i]);
212 val = strtod(str, NULL);
213 if (errno != 0 || val < 0) {
216 *value = (utime_t)(val * mult[i]);
221 * Edit a utime "duration" into ASCII
223 char *edit_utime(utime_t val, char *buf)
226 static const int32_t mult[] = {60*60*24*365, 60*60*24*30, 60*60*24, 60*60, 60};
227 static const char *mod[] = {"year", "month", "day", "hour", "min"};
232 for (i=0; i<5; i++) {
233 times = (uint32_t)(val / mult[i]);
235 val = val - (utime_t)times * mult[i];
236 sprintf(mybuf, "%d %s%s ", times, mod[i], times>1?"s":"");
240 if (val == 0 && strlen(buf) == 0) {
241 strcat(buf, "0 secs");
242 } else if (val != 0) {
243 sprintf(mybuf, "%d sec%s", (uint32_t)val, val>1?"s":"");
250 * Convert a size size in bytes to uint64_t
251 * Returns 0: if error
252 1: if OK, and value stored in value
254 int size_to_uint64(char *str, int str_len, uint64_t *value)
259 static const char *mod[] = {"*", "k", "kb", "m", "mb", "g", "gb", NULL}; /* first item * not used */
260 const int64_t mult[] = {1, /* byte */
262 1000, /* kb kilobyte */
263 1048576, /* megabyte */
264 1000000, /* mb megabyte */
265 1073741824, /* gigabyte */
266 1000000000}; /* gb gigabyte */
268 if (!get_modifier(str, mod_str, sizeof(mod_str))) {
271 /* Now find the multiplier corresponding to the modifier */
272 mod_len = strlen(mod_str);
273 for (i=0; mod[i]; i++) {
274 if (strncasecmp(mod_str, mod[i], mod_len) == 0) {
278 if (mod[i] == NULL) {
279 i = 0; /* no modifier found, assume 1 */
281 Dmsg2(900, "str=%s: mult=%d\n", str, mult[i]);
283 val = strtod(str, NULL);
284 if (errno != 0 || val < 0) {
287 *value = (utime_t)(val * mult[i]);
292 * Check if specified string is a number or not.
293 * Taken from SQLite, cool, thanks.
295 int is_a_number(const char *n)
297 bool digit_seen = false;
299 if( *n == '-' || *n == '+' ) {
302 while (B_ISDIGIT(*n)) {
306 if (digit_seen && *n == '.') {
308 while (B_ISDIGIT(*n)) { n++; }
310 if (digit_seen && (*n == 'e' || *n == 'E')
311 && (B_ISDIGIT(n[1]) || ((n[1]=='-' || n[1] == '+') && B_ISDIGIT(n[2])))) {
312 n += 2; /* skip e- or e+ or e digit */
313 while (B_ISDIGIT(*n)) { n++; }
315 return digit_seen && *n==0;
319 * Check if the specified string is an integer
321 int is_an_integer(const char *n)
323 bool digit_seen = false;
324 while (B_ISDIGIT(*n)) {
328 return digit_seen && *n==0;
332 * Check if Bacula Resoure Name is valid
335 * Check if the Volume name has legal characters
336 * If ua is non-NULL send the message
338 bool is_name_valid(char *name, POOLMEM **msg)
342 /* Special characters to accept */
343 const char *accept = ":.-_ ";
345 /* Restrict the characters permitted in the Volume name */
346 for (p=name; *p; p++) {
347 if (B_ISALPHA(*p) || B_ISDIGIT(*p) || strchr(accept, (int)(*p))) {
351 Mmsg(msg, _("Illegal character \"%c\" in name.\n"), *p);
356 if (len >= MAX_NAME_LENGTH) {
358 Mmsg(msg, _("Name too long.\n"));
364 Mmsg(msg, _("Volume name must be at least one character long.\n"));
374 * Add commas to a string, which is presumably
377 char *add_commas(char *val, char *buf)
395 for (i=0; i < 3; i++) {
404 void d_msg(const char*, int, int, const char*, ...)
406 int main(int argc, char *argv[])
408 char *str[] = {"3", "3n", "3 hours", "3.5 day", "3 week", "3 m", "3 q", "3 years"};
413 for (int i=0; i<8; i++) {
415 if (!duration_to_utime(buf, &val)) {
416 printf("Error return from duration_to_utime for in=%s\n", str[i]);
419 edit_utime(val, outval);
420 printf("in=%s val=%" lld " outval=%s\n", str[i], val, outval);