]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/sellist.c
3f58de04ecdc28b68cb45f0ae6b0d702f002e399
[bacula/bacula] / bacula / src / lib / sellist.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2011-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *  Kern Sibbald, January  MMXII
18  *
19  *  Selection list. A string of integers separated by commas
20  *   representing items selected. Ranges of the form nn-mm
21  *   are also permitted.
22  */
23
24 #include "bacula.h"
25
26 /*
27  * Returns next item
28  *   error if returns -1 and errmsg set
29  *   end of items if returns -1 and errmsg NULL
30  */
31 int64_t sellist::next()
32 {
33    errmsg = NULL;
34    if (beg <= end) {
35       return beg++;
36    }
37    if (e == NULL) {
38       goto bail_out;
39    }
40    /*
41     * As we walk the list, we set EOF in
42     *   the end of the next item to ease scanning,
43     *   but save and then restore the character.
44     */
45    for (p=e; p && *p; p=e) {
46       /* Check for list */
47       e = strchr(p, ',');
48       if (e) {                       /* have list */
49          esave = *e;
50          *e++ = 0;
51       } else {
52          esave = 0;
53       }
54       /* Check for range */
55       h = strchr(p, '-');             /* range? */
56       if (h == p) {
57          errmsg = _("Negative numbers not permitted.\n");
58          goto bail_out;
59       }
60       if (h) {                        /* have range */
61          hsave = *h;
62          *h++ = 0;
63          if (!is_an_integer(h)) {
64             errmsg = _("Range end is not integer.\n");
65             goto bail_out;
66          }
67          skip_spaces(&p);
68          if (!is_an_integer(p)) {
69             errmsg = _("Range start is not an integer.\n");
70             goto bail_out;
71          }
72          beg = str_to_int64(p);
73          end = str_to_int64(h);
74          if (end < beg) {
75             errmsg = _("Range end not bigger than start.\n");
76             goto bail_out;
77          }
78       } else {                           /* not list, not range */
79          hsave = 0;
80          skip_spaces(&p);
81          /* Check for abort (.) */
82          if (*p == '.') {
83             errmsg = _("User cancel requested.\n");
84             goto bail_out;
85          }
86          /* Check for all keyword */
87          if (strncasecmp(p, "all", 3) == 0) {
88             all = true;
89             errmsg = NULL;
90             return 0;
91          }
92          if (!is_an_integer(p)) {
93             errmsg = _("Input value is not an integer.\n");
94             goto bail_out;
95          }
96          beg = end = str_to_int64(p);
97       }
98       if (esave) {
99          *(e-1) = esave;
100       }
101       if (hsave) {
102          *(h-1) = hsave;
103       }
104       if (beg <= 0 || end <= 0) {
105          errmsg = _("Selection items must be be greater than zero.\n");
106          goto bail_out;
107       }
108       if (end > max) {
109          errmsg = _("Selection item too large.\n");
110          goto bail_out;
111       }
112       if (beg <= end) {
113          return beg++;
114       }
115    }
116    /* End of items */
117    errmsg = NULL;      /* No error */
118    return -1;
119
120 bail_out:
121    return -1;          /* Error, errmsg set */
122 }
123
124
125 /*
126  * Set selection string and optionally scan it
127  *   returns false on error in string
128  *   returns true if OK
129  */
130 bool sellist::set_string(char *string, bool scan=true)
131 {
132    /*
133     * Copy string, because we write into it,
134     *  then scan through it once to find any
135     *  errors.
136     */
137    if (expanded) {
138       free(expanded);
139       expanded = NULL;
140    }
141    if (str) {
142       free(str);
143    }
144    e = str = bstrdup(string);
145    end = 0;
146    beg = 1;
147    num_items = 0;
148    if (scan) {
149       while (next() >= 0) {
150          num_items++;
151       }
152       if (get_errmsg()) {
153          return false;
154       }
155       e = str;
156       end = 0;
157       beg = 1;
158    }
159    return true;
160 }
161
162 /* Get the expanded list of all ids, very useful for SQL queries */
163 char *sellist::get_expanded_list()
164 {
165    int32_t expandedsize = 512;
166    int32_t len;
167    int64_t val;
168    char    *p, *tmp;
169    char    ed1[50];
170
171    if (!expanded) {
172       p = expanded = (char *)malloc(expandedsize * sizeof(char));
173       *p = 0;
174
175       while ((val = next()) >= 0) {
176          edit_int64(val, ed1);
177          len = strlen(ed1);
178
179          /* Alloc more space if needed */
180          if ((p + len + 1) > (expanded + expandedsize)) {
181             expandedsize = expandedsize * 2;
182
183             tmp = (char *) realloc(expanded, expandedsize);
184
185             /* Compute new addresses for p and expanded */
186             p = tmp + (p - expanded);
187             expanded = tmp;
188          }
189
190          /* If not at the begining of the string, add a "," */
191          if (p != expanded) {
192             strcpy(p, ",");
193             p++;
194          }
195
196          strcpy(p, ed1);
197          p += len;
198       }
199    }
200    return expanded;
201 }
202
203 #ifdef TEST_PROGRAM
204 int main(int argc, char **argv, char **env)
205 {
206    const char *msg;
207    sellist sl;
208    int i;
209
210    if (!argv[1]) {
211       msg = _("No input string given.\n");
212       goto bail_out;
213    }
214    Dmsg1(000, "argv[1]=%s\n", argv[1]);
215
216    strip_trailing_junk(argv[1]);
217    sl.set_string(argv[1]);
218
219    //Dmsg1(000, "get_list=%s\n", sl.get_list());
220
221    /* If the list is very long, Dmsg will truncate it */
222    Dmsg1(000, "get_expanded_list=%s\n", NPRT(sl.get_expanded_list()));
223
224    if ((msg = sl.get_errmsg())) {
225       goto bail_out;
226    }
227    while ((i=sl.next()) > 0) {
228       Dmsg1(000, "rtn=%d\n", i);
229    }
230    if ((msg = sl.get_errmsg())) {
231       goto bail_out;
232    }
233    printf("\nPass 2 argv[1]=%s\n", argv[1]);
234    sl.set_string(argv[1]);
235    while ((i=sl.next()) > 0) {
236       Dmsg1(000, "rtn=%d\n", i);
237    }
238    msg = sl.get_errmsg();
239    Dmsg2(000, "rtn=%d msg=%s\n", i, NPRT(msg));
240    if (msg) {
241       goto bail_out;
242    }
243    return 0;
244
245 bail_out:
246    Dmsg1(000, "Error: %s\n", NPRT(msg));
247    return 1;
248
249 }
250 #endif /* TEST_PROGRAM */