]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/sellist.c
Fix Bacula bug #2046 -- sellist limited to 10000
[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 (beg <= end) {
109          return beg++;
110       }
111    }
112    /* End of items */
113    errmsg = NULL;      /* No error */
114    return -1;
115
116 bail_out:
117    return -1;          /* Error, errmsg set */
118 }
119
120
121 /*
122  * Set selection string and optionally scan it
123  *   returns false on error in string
124  *   returns true if OK
125  */
126 bool sellist::set_string(char *string, bool scan=true)
127 {
128    /*
129     * Copy string, because we write into it,
130     *  then scan through it once to find any
131     *  errors.
132     */
133    if (expanded) {
134       free(expanded);
135       expanded = NULL;
136    }
137    if (str) {
138       free(str);
139    }
140    e = str = bstrdup(string);
141    end = 0;
142    beg = 1;
143    num_items = 0;
144    if (scan) {
145       while (next() >= 0) {
146          num_items++;
147       }
148       if (get_errmsg()) {
149          return false;
150       }
151       e = str;
152       end = 0;
153       beg = 1;
154    }
155    return true;
156 }
157
158 /* Get the expanded list of all ids, very useful for SQL queries */
159 char *sellist::get_expanded_list()
160 {
161    int32_t expandedsize = 512;
162    int32_t len;
163    int64_t val;
164    char    *p, *tmp;
165    char    ed1[50];
166
167    if (!expanded) {
168       p = expanded = (char *)malloc(expandedsize * sizeof(char));
169       *p = 0;
170
171       while ((val = next()) >= 0) {
172          edit_int64(val, ed1);
173          len = strlen(ed1);
174
175          /* Alloc more space if needed */
176          if ((p + len + 1) > (expanded + expandedsize)) {
177             expandedsize = expandedsize * 2;
178
179             tmp = (char *) realloc(expanded, expandedsize);
180
181             /* Compute new addresses for p and expanded */
182             p = tmp + (p - expanded);
183             expanded = tmp;
184          }
185
186          /* If not at the begining of the string, add a "," */
187          if (p != expanded) {
188             strcpy(p, ",");
189             p++;
190          }
191
192          strcpy(p, ed1);
193          p += len;
194       }
195    }
196    return expanded;
197 }
198
199 #ifdef TEST_PROGRAM
200 int main(int argc, char **argv, char **env)
201 {
202    const char *msg;
203    sellist sl;
204    int i;
205
206    if (!argv[1]) {
207       msg = _("No input string given.\n");
208       goto bail_out;
209    }
210    Dmsg1(000, "argv[1]=%s\n", argv[1]);
211
212    strip_trailing_junk(argv[1]);
213    sl.set_string(argv[1]);
214
215    //Dmsg1(000, "get_list=%s\n", sl.get_list());
216
217    /* If the list is very long, Dmsg will truncate it */
218    Dmsg1(000, "get_expanded_list=%s\n", NPRT(sl.get_expanded_list()));
219
220    if ((msg = sl.get_errmsg())) {
221       goto bail_out;
222    }
223    while ((i=sl.next()) > 0) {
224       Dmsg1(000, "rtn=%d\n", i);
225    }
226    if ((msg = sl.get_errmsg())) {
227       goto bail_out;
228    }
229    printf("\nPass 2 argv[1]=%s\n", argv[1]);
230    sl.set_string(argv[1]);
231    while ((i=sl.next()) > 0) {
232       Dmsg1(000, "rtn=%d\n", i);
233    }
234    msg = sl.get_errmsg();
235    Dmsg2(000, "rtn=%d msg=%s\n", i, NPRT(msg));
236    if (msg) {
237       goto bail_out;
238    }
239    return 0;
240
241 bail_out:
242    Dmsg1(000, "Error: %s\n", NPRT(msg));
243    return 1;
244
245 }
246 #endif /* TEST_PROGRAM */