2 * Master Configuration routines.
4 * This file contains the common parts of the Bacula
5 * configuration routines.
7 * Note, the configuration file parser consists of three parts
9 * 1. The generic lexical scanner in lib/lex.c and lib/lex.h
11 * 2. The generic config scanner in lib/parse_conf.c and
13 * These files contain the parser code, some utility
14 * routines, and the common store routines (name, int,
15 * string, time, int64, size, ...).
17 * 3. The daemon specific file, which contains the Resource
18 * definitions as well as any specific store routines
19 * for the resource records.
21 * N.B. This is a two pass parser, so if you malloc() a string
22 * in a "store" routine, you must ensure to do it during
23 * only one of the two passes, or to free it between.
24 * Also, note that the resource record is malloced and
25 * saved in save_resource() during pass 1. Anything that
26 * you want saved after pass two (e.g. resource pointers)
27 * must explicitly be done in save_resource. Take a look
28 * at the Job resource in src/dird/dird_conf.c to see how
31 * Kern Sibbald, January MM
36 Copyright (C) 2000-2006 Kern Sibbald
38 This program is free software; you can redistribute it and/or
39 modify it under the terms of the GNU General Public License
40 version 2 as amended with additional clauses defined in the
41 file LICENSE in the main source directory.
43 This program is distributed in the hope that it will be useful,
44 but WITHOUT ANY WARRANTY; without even the implied warranty of
45 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
46 the file LICENSE for additional details.
53 extern int debug_level;
55 /* Each daemon has a slightly different set of
56 * resources, so it will define the following
61 extern RES_TABLE resources[];
62 extern RES **res_head;
65 // work around visual studio name manling preventing external linkage since res_all
66 // is declared as a different type when instantiated.
67 extern "C" CURES res_all;
68 extern "C" int res_all_size;
71 extern int res_all_size;
74 extern brwlock_t res_lock; /* resource lock */
77 /* Forward referenced subroutines */
78 static void scan_types(LEX *lc, MSGS *msg, int dest, char *where, char *cmd);
81 /* Common Resource definitions */
83 /* Message resource directives
84 * name handler value code flags default_value
86 RES_ITEM msgs_items[] = {
87 {"name", store_name, ITEM(res_msgs.hdr.name), 0, 0, 0},
88 {"description", store_str, ITEM(res_msgs.hdr.desc), 0, 0, 0},
89 {"mailcommand", store_str, ITEM(res_msgs.mail_cmd), 0, 0, 0},
90 {"operatorcommand", store_str, ITEM(res_msgs.operator_cmd), 0, 0, 0},
91 {"syslog", store_msgs, ITEM(res_msgs), MD_SYSLOG, 0, 0},
92 {"mail", store_msgs, ITEM(res_msgs), MD_MAIL, 0, 0},
93 {"mailonerror", store_msgs, ITEM(res_msgs), MD_MAIL_ON_ERROR, 0, 0},
94 {"file", store_msgs, ITEM(res_msgs), MD_FILE, 0, 0},
95 {"append", store_msgs, ITEM(res_msgs), MD_APPEND, 0, 0},
96 {"stdout", store_msgs, ITEM(res_msgs), MD_STDOUT, 0, 0},
97 {"stderr", store_msgs, ITEM(res_msgs), MD_STDERR, 0, 0},
98 {"director", store_msgs, ITEM(res_msgs), MD_DIRECTOR, 0, 0},
99 {"console", store_msgs, ITEM(res_msgs), MD_CONSOLE, 0, 0},
100 {"operator", store_msgs, ITEM(res_msgs), MD_OPERATOR, 0, 0},
101 {NULL, NULL, NULL, 0, 0}
108 /* Various message types */
109 static struct s_mtypes msg_types[] = {
114 {"warning", M_WARNING},
117 {"notsaved", M_NOTSAVED},
118 {"skipped", M_SKIPPED},
120 {"terminate", M_TERM},
121 {"restored", M_RESTORED},
122 {"security", M_SECURITY},
128 /* Used for certain KeyWord tables */
135 * Tape Label types permitted in Pool records
137 * tape label label code = token
139 static s_kw tapelabels[] = {
140 {"bacula", B_BACULA_LABEL},
141 {"ansi", B_ANSI_LABEL},
142 {"ibm", B_IBM_LABEL},
147 /* Simply print a message */
148 static void prtmsg(void *sock, const char *fmt, ...)
152 va_start(arg_ptr, fmt);
153 vfprintf(stdout, fmt, arg_ptr);
157 const char *res_to_str(int rcode)
159 if (rcode < r_first || rcode > r_last) {
160 return _("***UNKNOWN***");
162 return resources[rcode-r_first].name;
168 * Initialize the static structure to zeros, then
169 * apply all the default values.
171 void init_resource(int type, RES_ITEM *items, int pass)
174 int rindex = type - r_first;
175 static bool first = true;
178 if (first && (errstat=rwl_init(&res_lock)) != 0) {
179 Emsg1(M_ABORT, 0, _("Unable to initialize resource lock. ERR=%s\n"),
184 memset(&res_all, 0, res_all_size);
185 res_all.hdr.rcode = type;
186 res_all.hdr.refcnt = 1;
188 /* Set defaults in each item */
189 for (i=0; items[i].name; i++) {
190 Dmsg3(900, "Item=%s def=%s defval=%d\n", items[i].name,
191 (items[i].flags & ITEM_DEFAULT) ? "yes" : "no",
192 items[i].default_value);
193 if (items[i].flags & ITEM_DEFAULT && items[i].default_value != 0) {
194 if (items[i].handler == store_bit) {
195 *(int *)(items[i].value) |= items[i].code;
196 } else if (items[i].handler == store_bool) {
197 *(bool *)(items[i].value) = items[i].default_value;
198 } else if (items[i].handler == store_pint ||
199 items[i].handler == store_int) {
200 *(int *)(items[i].value) = items[i].default_value;
201 } else if (items[i].handler == store_int64) {
202 *(int64_t *)(items[i].value) = items[i].default_value;
203 } else if (items[i].handler == store_size) {
204 *(uint64_t *)(items[i].value) = (uint64_t)items[i].default_value;
205 } else if (items[i].handler == store_time) {
206 *(utime_t *)(items[i].value) = (utime_t)items[i].default_value;
207 } else if (pass == 1 && items[i].handler == store_addresses) {
208 init_default_addresses((dlist**)items[i].value, items[i].default_value);
211 /* If this triggers, take a look at lib/parse_conf.h */
212 if (i >= MAX_RES_ITEMS) {
213 Emsg1(M_ERROR_TERM, 0, _("Too many items in %s resource\n"), resources[rindex]);
219 /* Store Messages Destination information */
220 void store_msgs(LEX *lc, RES_ITEM *item, int index, int pass)
227 Dmsg2(900, "store_msgs pass=%d code=%d\n", pass, item->code);
229 switch (item->code) {
232 case MD_SYSLOG: /* syslog */
234 scan_types(lc, (MSGS *)(item->value), item->code, NULL, NULL);
236 case MD_OPERATOR: /* send to operator */
237 case MD_DIRECTOR: /* send to Director */
238 case MD_MAIL: /* mail */
239 case MD_MAIL_ON_ERROR: /* mail if Job errors */
240 if (item->code == MD_OPERATOR) {
241 cmd = res_all.res_msgs.operator_cmd;
243 cmd = res_all.res_msgs.mail_cmd;
245 dest = get_pool_memory(PM_MESSAGE);
248 /* Pick up comma separated list of destinations */
250 token = lex_get_token(lc, T_NAME); /* scan destination */
251 dest = check_pool_memory_size(dest, dest_len + lc->str_len + 2);
253 pm_strcat(dest, " "); /* separate multiple destinations with space */
256 pm_strcat(dest, lc->str);
257 dest_len += lc->str_len;
258 Dmsg2(900, "store_msgs newdest=%s: dest=%s:\n", lc->str, NPRT(dest));
259 token = lex_get_token(lc, T_SKIP_EOL);
260 if (token == T_COMMA) {
261 continue; /* get another destination */
263 if (token != T_EQUALS) {
264 scan_err1(lc, _("expected an =, got: %s"), lc->str);
268 Dmsg1(900, "mail_cmd=%s\n", NPRT(cmd));
269 scan_types(lc, (MSGS *)(item->value), item->code, dest, cmd);
270 free_pool_memory(dest);
271 Dmsg0(900, "done with dest codes\n");
273 case MD_FILE: /* file */
274 case MD_APPEND: /* append */
275 dest = get_pool_memory(PM_MESSAGE);
276 /* Pick up a single destination */
277 token = lex_get_token(lc, T_NAME); /* scan destination */
278 pm_strcpy(dest, lc->str);
279 dest_len = lc->str_len;
280 token = lex_get_token(lc, T_SKIP_EOL);
281 Dmsg1(900, "store_msgs dest=%s:\n", NPRT(dest));
282 if (token != T_EQUALS) {
283 scan_err1(lc, _("expected an =, got: %s"), lc->str);
285 scan_types(lc, (MSGS *)(item->value), item->code, dest, NULL);
286 free_pool_memory(dest);
287 Dmsg0(900, "done with dest codes\n");
291 scan_err1(lc, _("Unknown item code: %d\n"), item->code);
296 set_bit(index, res_all.hdr.item_present);
297 Dmsg0(900, "Done store_msgs\n");
301 * Scan for message types and add them to the message
302 * destination. The basic job here is to connect message types
303 * (WARNING, ERROR, FATAL, INFO, ...) with an appropriate
304 * destination (MAIL, FILE, OPERATOR, ...)
306 static void scan_types(LEX *lc, MSGS *msg, int dest_code, char *where, char *cmd)
308 int i, found, quit, is_not;
312 for (quit=0; !quit;) {
313 lex_get_token(lc, T_NAME); /* expect at least one type */
315 if (lc->str[0] == '!') {
322 for (i=0; msg_types[i].name; i++) {
323 if (strcasecmp(str, msg_types[i].name) == 0) {
324 msg_type = msg_types[i].token;
330 scan_err1(lc, _("message type: %s not found"), str);
334 if (msg_type == M_MAX+1) { /* all? */
335 for (i=1; i<=M_MAX; i++) { /* yes set all types */
336 add_msg_dest(msg, dest_code, i, where, cmd);
340 rem_msg_dest(msg, dest_code, msg_type, where);
342 add_msg_dest(msg, dest_code, msg_type, where, cmd);
348 Dmsg0(900, "call lex_get_token() to eat comma\n");
349 lex_get_token(lc, T_ALL); /* eat comma */
351 Dmsg0(900, "Done scan_types()\n");
356 * This routine is ONLY for resource names
357 * Store a name at specified address.
359 void store_name(LEX *lc, RES_ITEM *item, int index, int pass)
361 POOLMEM *msg = get_pool_memory(PM_EMSG);
362 lex_get_token(lc, T_NAME);
363 if (!is_name_valid(lc->str, &msg)) {
364 scan_err1(lc, "%s\n", msg);
366 free_pool_memory(msg);
367 /* Store the name both pass 1 and pass 2 */
368 if (*(item->value)) {
369 scan_err2(lc, _("Attempt to redefine name \"%s\" to \"%s\"."),
370 *(item->value), lc->str);
372 *(item->value) = bstrdup(lc->str);
374 set_bit(index, res_all.hdr.item_present);
379 * Store a name string at specified address
380 * A name string is limited to MAX_RES_NAME_LENGTH
382 void store_strname(LEX *lc, RES_ITEM *item, int index, int pass)
384 lex_get_token(lc, T_NAME);
387 *(item->value) = bstrdup(lc->str);
390 set_bit(index, res_all.hdr.item_present);
393 /* Store a string at specified address */
394 void store_str(LEX *lc, RES_ITEM *item, int index, int pass)
396 lex_get_token(lc, T_STRING);
398 *(item->value) = bstrdup(lc->str);
401 set_bit(index, res_all.hdr.item_present);
405 * Store a directory name at specified address. Note, we do
406 * shell expansion except if the string begins with a vertical
407 * bar (i.e. it will likely be passed to the shell later).
409 void store_dir(LEX *lc, RES_ITEM *item, int index, int pass)
411 lex_get_token(lc, T_STRING);
413 if (lc->str[0] != '|') {
414 do_shell_expansion(lc->str, sizeof(lc->str));
416 *(item->value) = bstrdup(lc->str);
419 set_bit(index, res_all.hdr.item_present);
423 /* Store a password specified address in MD5 coding */
424 void store_password(LEX *lc, RES_ITEM *item, int index, int pass)
427 struct MD5Context md5c;
428 unsigned char digest[CRYPTO_DIGEST_MD5_SIZE];
432 lex_get_token(lc, T_STRING);
435 MD5Update(&md5c, (unsigned char *) (lc->str), lc->str_len);
436 MD5Final(digest, &md5c);
437 for (i = j = 0; i < sizeof(digest); i++) {
438 sprintf(&sig[j], "%02x", digest[i]);
441 *(item->value) = bstrdup(sig);
444 set_bit(index, res_all.hdr.item_present);
448 /* Store a resource at specified address.
449 * If we are in pass 2, do a lookup of the
452 void store_res(LEX *lc, RES_ITEM *item, int index, int pass)
456 lex_get_token(lc, T_NAME);
458 res = GetResWithName(item->code, lc->str);
460 scan_err3(lc, _("Could not find config Resource %s referenced on line %d : %s\n"),
461 lc->str, lc->line_no, lc->line);
463 if (*(item->value)) {
464 scan_err3(lc, _("Attempt to redefine resource \"%s\" referenced on line %d : %s\n"),
465 item->name, lc->line_no, lc->line);
467 *(item->value) = (char *)res;
470 set_bit(index, res_all.hdr.item_present);
474 * Store a resource pointer in an alist. default_value indicates how many
475 * times this routine can be called -- i.e. how many alists
477 * If we are in pass 2, do a lookup of the
480 void store_alist_res(LEX *lc, RES_ITEM *item, int index, int pass)
483 int count = item->default_value;
488 if (count == 0) { /* always store in item->value */
490 if ((item->value)[i] == NULL) {
491 list = New(alist(10, not_owned_by_alist));
493 list = (alist *)(item->value)[i];
496 /* Find empty place to store this directive */
497 while ((item->value)[i] != NULL && i++ < count) { }
499 scan_err4(lc, _("Too many %s directives. Max. is %d. line %d: %s\n"),
500 lc->str, count, lc->line_no, lc->line);
502 list = New(alist(10, not_owned_by_alist));
506 lex_get_token(lc, T_NAME); /* scan next item */
507 res = GetResWithName(item->code, lc->str);
509 scan_err3(lc, _("Could not find config Resource \"%s\" referenced on line %d : %s\n"),
510 item->name, lc->line_no, lc->line);
512 Dmsg5(900, "Append %p to alist %p size=%d i=%d %s\n",
513 res, list, list->size(), i, item->name);
515 (item->value)[i] = (char *)list;
516 if (lc->ch != ',') { /* if no other item follows */
519 lex_get_token(lc, T_ALL); /* eat comma */
523 set_bit(index, res_all.hdr.item_present);
528 * Store a string in an alist.
530 void store_alist_str(LEX *lc, RES_ITEM *item, int index, int pass)
535 if (*(item->value) == NULL) {
536 list = New(alist(10, owned_by_alist));
538 list = (alist *)(*(item->value));
541 lex_get_token(lc, T_STRING); /* scan next item */
542 Dmsg4(900, "Append %s to alist %p size=%d %s\n",
543 lc->str, list, list->size(), item->name);
544 list->append(bstrdup(lc->str));
545 *(item->value) = (char *)list;
548 set_bit(index, res_all.hdr.item_present);
554 * Store default values for Resource from xxxDefs
555 * If we are in pass 2, do a lookup of the
556 * resource and store everything not explicitly set
559 * Note, here item points to the main resource (e.g. Job, not
560 * the jobdefs, which we look up).
562 void store_defs(LEX *lc, RES_ITEM *item, int index, int pass)
566 lex_get_token(lc, T_NAME);
568 Dmsg2(900, "Code=%d name=%s\n", item->code, lc->str);
569 res = GetResWithName(item->code, lc->str);
571 scan_err3(lc, _("Missing config Resource \"%s\" referenced on line %d : %s\n"),
572 lc->str, lc->line_no, lc->line);
580 /* Store an integer at specified address */
581 void store_int(LEX *lc, RES_ITEM *item, int index, int pass)
583 lex_get_token(lc, T_INT32);
584 *(int *)(item->value) = lc->int32_val;
586 set_bit(index, res_all.hdr.item_present);
589 /* Store a positive integer at specified address */
590 void store_pint(LEX *lc, RES_ITEM *item, int index, int pass)
592 lex_get_token(lc, T_PINT32);
593 *(int *)(item->value) = lc->pint32_val;
595 set_bit(index, res_all.hdr.item_present);
599 /* Store an 64 bit integer at specified address */
600 void store_int64(LEX *lc, RES_ITEM *item, int index, int pass)
602 lex_get_token(lc, T_INT64);
603 *(int64_t *)(item->value) = lc->int64_val;
605 set_bit(index, res_all.hdr.item_present);
608 /* Store a size in bytes */
609 void store_size(LEX *lc, RES_ITEM *item, int index, int pass)
615 Dmsg0(900, "Enter store_size\n");
616 token = lex_get_token(lc, T_SKIP_EOL);
621 case T_UNQUOTED_STRING:
622 bstrncpy(bsize, lc->str, sizeof(bsize)); /* save first part */
623 /* if terminated by space, scan and get modifier */
624 while (lc->ch == ' ') {
625 token = lex_get_token(lc, T_ALL);
629 case T_UNQUOTED_STRING:
630 bstrncat(bsize, lc->str, sizeof(bsize));
634 if (!size_to_uint64(bsize, strlen(bsize), &uvalue)) {
635 scan_err1(lc, _("expected a size number, got: %s"), lc->str);
637 *(uint64_t *)(item->value) = uvalue;
640 scan_err1(lc, _("expected a size, got: %s"), lc->str);
643 if (token != T_EOL) {
646 set_bit(index, res_all.hdr.item_present);
647 Dmsg0(900, "Leave store_size\n");
651 /* Store a time period in seconds */
652 void store_time(LEX *lc, RES_ITEM *item, int index, int pass)
658 token = lex_get_token(lc, T_SKIP_EOL);
663 case T_UNQUOTED_STRING:
664 bstrncpy(period, lc->str, sizeof(period)); /* get first part */
665 /* if terminated by space, scan and get modifier */
666 while (lc->ch == ' ') {
667 token = lex_get_token(lc, T_ALL);
671 case T_UNQUOTED_STRING:
672 bstrncat(period, lc->str, sizeof(period));
676 if (!duration_to_utime(period, &utime)) {
677 scan_err1(lc, _("expected a time period, got: %s"), period);
679 *(utime_t *)(item->value) = utime;
682 scan_err1(lc, _("expected a time period, got: %s"), lc->str);
685 if (token != T_EOL) {
688 set_bit(index, res_all.hdr.item_present);
692 /* Store a yes/no in a bit field */
693 void store_bit(LEX *lc, RES_ITEM *item, int index, int pass)
695 lex_get_token(lc, T_NAME);
696 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
697 *(int *)(item->value) |= item->code;
698 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
699 *(int *)(item->value) &= ~(item->code);
701 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
704 set_bit(index, res_all.hdr.item_present);
707 /* Store a bool in a bit field */
708 void store_bool(LEX *lc, RES_ITEM *item, int index, int pass)
710 lex_get_token(lc, T_NAME);
711 if (strcasecmp(lc->str, "yes") == 0 || strcasecmp(lc->str, "true") == 0) {
712 *(bool *)(item->value) = true;
713 } else if (strcasecmp(lc->str, "no") == 0 || strcasecmp(lc->str, "false") == 0) {
714 *(bool *)(item->value) = false;
716 scan_err2(lc, _("Expect %s, got: %s"), "YES, NO, TRUE, or FALSE", lc->str); /* YES and NO must not be translated */
719 set_bit(index, res_all.hdr.item_present);
724 * Store Tape Label Type (Bacula, ANSI, IBM)
727 void store_label(LEX *lc, RES_ITEM *item, int index, int pass)
731 token = lex_get_token(lc, T_NAME);
732 /* Store the label pass 2 so that type is defined */
733 for (i=0; tapelabels[i].name; i++) {
734 if (strcasecmp(lc->str, tapelabels[i].name) == 0) {
735 *(int *)(item->value) = tapelabels[i].token;
741 scan_err1(lc, _("Expected a Tape Label keyword, got: %s"), lc->str);
744 set_bit(index, res_all.hdr.item_present);
754 /*********************************************************************
756 * Parse configuration file
758 * Return 0 if reading failed, 1 otherwise
759 * Note, the default behavior unless you have set an alternate
760 * scan_error handler is to die on an error.
763 parse_config(const char *cf, LEX_ERROR_HANDLER *scan_error)
768 enum parse_state state = p_none;
769 RES_ITEM *items = NULL;
772 /* Make two passes. The first builds the name symbol table,
773 * and the second picks up the items.
775 Dmsg0(900, "Enter parse_config()\n");
776 for (pass=1; pass <= 2; pass++) {
777 Dmsg1(900, "parse_config pass %d\n", pass);
778 if ((lc = lex_open_file(lc, cf, scan_error)) == NULL) {
780 /* We must create a lex packet to print the error */
781 lc = (LEX *)malloc(sizeof(LEX));
782 memset(lc, 0, sizeof(LEX));
784 lc->scan_error = scan_error;
786 lex_set_default_error_handler(lc);
788 bstrncpy(lc->str, cf, sizeof(lc->str));
790 scan_err2(lc, _("Cannot open config file \"%s\": %s\n"),
791 lc->str, be.strerror());
795 while ((token=lex_get_token(lc, T_ALL)) != T_EOF) {
796 Dmsg1(900, "parse got token=%s\n", lex_tok_to_str(token));
799 if (token == T_EOL) {
802 if (token != T_IDENTIFIER) {
803 scan_err1(lc, _("Expected a Resource name identifier, got: %s"), lc->str);
806 for (i=0; resources[i].name; i++)
807 if (strcasecmp(resources[i].name, lc->str) == 0) {
809 items = resources[i].items;
810 res_type = resources[i].rcode;
811 init_resource(res_type, items, pass);
814 if (state == p_none) {
815 scan_err1(lc, _("expected resource name, got: %s"), lc->str);
826 scan_err1(lc, _("not in resource definition: %s"), lc->str);
829 for (i=0; items[i].name; i++) {
830 if (strcasecmp(items[i].name, lc->str) == 0) {
831 /* If the ITEM_NO_EQUALS flag is set we do NOT
832 * scan for = after the keyword */
833 if (!(items[i].flags & ITEM_NO_EQUALS)) {
834 token = lex_get_token(lc, T_SKIP_EOL);
835 Dmsg1 (900, "in T_IDENT got token=%s\n", lex_tok_to_str(token));
836 if (token != T_EQUALS) {
837 scan_err1(lc, _("expected an equals, got: %s"), lc->str);
841 Dmsg1(800, "calling handler for %s\n", items[i].name);
842 /* Call item handler */
843 items[i].handler(lc, &items[i], i, pass);
849 Dmsg2(900, "level=%d id=%s\n", level, lc->str);
850 Dmsg1(900, "Keyword = %s\n", lc->str);
851 scan_err1(lc, _("Keyword \"%s\" not permitted in this resource.\n"
852 "Perhaps you left the trailing brace off of the previous resource."), lc->str);
860 Dmsg0(900, "T_EOB => define new resource\n");
861 save_resource(res_type, items, pass); /* save resource */
868 scan_err2(lc, _("unexpected token %d %s in resource definition"),
869 token, lex_tok_to_str(token));
874 scan_err1(lc, _("Unknown parser state %d\n"), state);
878 if (state != p_none) {
879 scan_err0(lc, _("End of conf file reached with unclosed resource."));
882 if (debug_level >= 900 && pass == 2) {
884 for (i=r_first; i<=r_last; i++) {
885 dump_resource(i, res_head[i-r_first], prtmsg, NULL);
888 lc = lex_close_file(lc);
890 Dmsg0(900, "Leave parse_config()\n");
894 /*********************************************************************
896 * Free configuration resources
899 void free_config_resources()
901 for (int i=r_first; i<=r_last; i++) {
902 free_resource(res_head[i-r_first], i);
903 res_head[i-r_first] = NULL;
907 RES **save_config_resources()
909 int num = r_last - r_first + 1;
910 RES **res = (RES **)malloc(num*sizeof(RES *));
911 for (int i=0; i<num; i++) {
912 res[i] = res_head[i];
920 int size = (r_last - r_first + 1) * sizeof(RES *);
921 RES **res = (RES **)malloc(size);
922 memset(res, 0, size);