File:  [Qemu by Fabrice Bellard] / qemu / qemu-option.c
Revision 1.1.1.5 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 19:16:28 2018 UTC (2 years, 6 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu1001, HEAD
qemu 1.0.1

    1: /*
    2:  * Commandline option parsing functions
    3:  *
    4:  * Copyright (c) 2003-2008 Fabrice Bellard
    5:  * Copyright (c) 2009 Kevin Wolf <kwolf@redhat.com>
    6:  *
    7:  * Permission is hereby granted, free of charge, to any person obtaining a copy
    8:  * of this software and associated documentation files (the "Software"), to deal
    9:  * in the Software without restriction, including without limitation the rights
   10:  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
   11:  * copies of the Software, and to permit persons to whom the Software is
   12:  * furnished to do so, subject to the following conditions:
   13:  *
   14:  * The above copyright notice and this permission notice shall be included in
   15:  * all copies or substantial portions of the Software.
   16:  *
   17:  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   18:  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   19:  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   20:  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   21:  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   22:  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   23:  * THE SOFTWARE.
   24:  */
   25: 
   26: #include <stdio.h>
   27: #include <string.h>
   28: 
   29: #include "qemu-common.h"
   30: #include "qemu-error.h"
   31: #include "qemu-objects.h"
   32: #include "qemu-option.h"
   33: #include "qerror.h"
   34: 
   35: /*
   36:  * Extracts the name of an option from the parameter string (p points at the
   37:  * first byte of the option name)
   38:  *
   39:  * The option name is delimited by delim (usually , or =) or the string end
   40:  * and is copied into buf. If the option name is longer than buf_size, it is
   41:  * truncated. buf is always zero terminated.
   42:  *
   43:  * The return value is the position of the delimiter/zero byte after the option
   44:  * name in p.
   45:  */
   46: const char *get_opt_name(char *buf, int buf_size, const char *p, char delim)
   47: {
   48:     char *q;
   49: 
   50:     q = buf;
   51:     while (*p != '\0' && *p != delim) {
   52:         if (q && (q - buf) < buf_size - 1)
   53:             *q++ = *p;
   54:         p++;
   55:     }
   56:     if (q)
   57:         *q = '\0';
   58: 
   59:     return p;
   60: }
   61: 
   62: /*
   63:  * Extracts the value of an option from the parameter string p (p points at the
   64:  * first byte of the option value)
   65:  *
   66:  * This function is comparable to get_opt_name with the difference that the
   67:  * delimiter is fixed to be comma which starts a new option. To specify an
   68:  * option value that contains commas, double each comma.
   69:  */
   70: const char *get_opt_value(char *buf, int buf_size, const char *p)
   71: {
   72:     char *q;
   73: 
   74:     q = buf;
   75:     while (*p != '\0') {
   76:         if (*p == ',') {
   77:             if (*(p + 1) != ',')
   78:                 break;
   79:             p++;
   80:         }
   81:         if (q && (q - buf) < buf_size - 1)
   82:             *q++ = *p;
   83:         p++;
   84:     }
   85:     if (q)
   86:         *q = '\0';
   87: 
   88:     return p;
   89: }
   90: 
   91: int get_next_param_value(char *buf, int buf_size,
   92:                          const char *tag, const char **pstr)
   93: {
   94:     const char *p;
   95:     char option[128];
   96: 
   97:     p = *pstr;
   98:     for(;;) {
   99:         p = get_opt_name(option, sizeof(option), p, '=');
  100:         if (*p != '=')
  101:             break;
  102:         p++;
  103:         if (!strcmp(tag, option)) {
  104:             *pstr = get_opt_value(buf, buf_size, p);
  105:             if (**pstr == ',') {
  106:                 (*pstr)++;
  107:             }
  108:             return strlen(buf);
  109:         } else {
  110:             p = get_opt_value(NULL, 0, p);
  111:         }
  112:         if (*p != ',')
  113:             break;
  114:         p++;
  115:     }
  116:     return 0;
  117: }
  118: 
  119: int get_param_value(char *buf, int buf_size,
  120:                     const char *tag, const char *str)
  121: {
  122:     return get_next_param_value(buf, buf_size, tag, &str);
  123: }
  124: 
  125: int check_params(char *buf, int buf_size,
  126:                  const char * const *params, const char *str)
  127: {
  128:     const char *p;
  129:     int i;
  130: 
  131:     p = str;
  132:     while (*p != '\0') {
  133:         p = get_opt_name(buf, buf_size, p, '=');
  134:         if (*p != '=') {
  135:             return -1;
  136:         }
  137:         p++;
  138:         for (i = 0; params[i] != NULL; i++) {
  139:             if (!strcmp(params[i], buf)) {
  140:                 break;
  141:             }
  142:         }
  143:         if (params[i] == NULL) {
  144:             return -1;
  145:         }
  146:         p = get_opt_value(NULL, 0, p);
  147:         if (*p != ',') {
  148:             break;
  149:         }
  150:         p++;
  151:     }
  152:     return 0;
  153: }
  154: 
  155: /*
  156:  * Searches an option list for an option with the given name
  157:  */
  158: QEMUOptionParameter *get_option_parameter(QEMUOptionParameter *list,
  159:     const char *name)
  160: {
  161:     while (list && list->name) {
  162:         if (!strcmp(list->name, name)) {
  163:             return list;
  164:         }
  165:         list++;
  166:     }
  167: 
  168:     return NULL;
  169: }
  170: 
  171: static int parse_option_bool(const char *name, const char *value, bool *ret)
  172: {
  173:     if (value != NULL) {
  174:         if (!strcmp(value, "on")) {
  175:             *ret = 1;
  176:         } else if (!strcmp(value, "off")) {
  177:             *ret = 0;
  178:         } else {
  179:             qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "'on' or 'off'");
  180:             return -1;
  181:         }
  182:     } else {
  183:         *ret = 1;
  184:     }
  185:     return 0;
  186: }
  187: 
  188: static int parse_option_number(const char *name, const char *value, uint64_t *ret)
  189: {
  190:     char *postfix;
  191:     uint64_t number;
  192: 
  193:     if (value != NULL) {
  194:         number = strtoull(value, &postfix, 0);
  195:         if (*postfix != '\0') {
  196:             qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a number");
  197:             return -1;
  198:         }
  199:         *ret = number;
  200:     } else {
  201:         qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a number");
  202:         return -1;
  203:     }
  204:     return 0;
  205: }
  206: 
  207: static int parse_option_size(const char *name, const char *value, uint64_t *ret)
  208: {
  209:     char *postfix;
  210:     double sizef;
  211: 
  212:     if (value != NULL) {
  213:         sizef = strtod(value, &postfix);
  214:         switch (*postfix) {
  215:         case 'T':
  216:             sizef *= 1024;
  217:         case 'G':
  218:             sizef *= 1024;
  219:         case 'M':
  220:             sizef *= 1024;
  221:         case 'K':
  222:         case 'k':
  223:             sizef *= 1024;
  224:         case 'b':
  225:         case '\0':
  226:             *ret = (uint64_t) sizef;
  227:             break;
  228:         default:
  229:             qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a size");
  230:             error_printf_unless_qmp("You may use k, M, G or T suffixes for "
  231:                     "kilobytes, megabytes, gigabytes and terabytes.\n");
  232:             return -1;
  233:         }
  234:     } else {
  235:         qerror_report(QERR_INVALID_PARAMETER_VALUE, name, "a size");
  236:         return -1;
  237:     }
  238:     return 0;
  239: }
  240: 
  241: /*
  242:  * Sets the value of a parameter in a given option list. The parsing of the
  243:  * value depends on the type of option:
  244:  *
  245:  * OPT_FLAG (uses value.n):
  246:  *      If no value is given, the flag is set to 1.
  247:  *      Otherwise the value must be "on" (set to 1) or "off" (set to 0)
  248:  *
  249:  * OPT_STRING (uses value.s):
  250:  *      value is strdup()ed and assigned as option value
  251:  *
  252:  * OPT_SIZE (uses value.n):
  253:  *      The value is converted to an integer. Suffixes for kilobytes etc. are
  254:  *      allowed (powers of 1024).
  255:  *
  256:  * Returns 0 on succes, -1 in error cases
  257:  */
  258: int set_option_parameter(QEMUOptionParameter *list, const char *name,
  259:     const char *value)
  260: {
  261:     bool flag;
  262: 
  263:     // Find a matching parameter
  264:     list = get_option_parameter(list, name);
  265:     if (list == NULL) {
  266:         fprintf(stderr, "Unknown option '%s'\n", name);
  267:         return -1;
  268:     }
  269: 
  270:     // Process parameter
  271:     switch (list->type) {
  272:     case OPT_FLAG:
  273:         if (parse_option_bool(name, value, &flag) == -1)
  274:             return -1;
  275:         list->value.n = flag;
  276:         break;
  277: 
  278:     case OPT_STRING:
  279:         if (value != NULL) {
  280:             list->value.s = g_strdup(value);
  281:         } else {
  282:             fprintf(stderr, "Option '%s' needs a parameter\n", name);
  283:             return -1;
  284:         }
  285:         break;
  286: 
  287:     case OPT_SIZE:
  288:         if (parse_option_size(name, value, &list->value.n) == -1)
  289:             return -1;
  290:         break;
  291: 
  292:     default:
  293:         fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);
  294:         return -1;
  295:     }
  296: 
  297:     return 0;
  298: }
  299: 
  300: /*
  301:  * Sets the given parameter to an integer instead of a string.
  302:  * This function cannot be used to set string options.
  303:  *
  304:  * Returns 0 on success, -1 in error cases
  305:  */
  306: int set_option_parameter_int(QEMUOptionParameter *list, const char *name,
  307:     uint64_t value)
  308: {
  309:     // Find a matching parameter
  310:     list = get_option_parameter(list, name);
  311:     if (list == NULL) {
  312:         fprintf(stderr, "Unknown option '%s'\n", name);
  313:         return -1;
  314:     }
  315: 
  316:     // Process parameter
  317:     switch (list->type) {
  318:     case OPT_FLAG:
  319:     case OPT_NUMBER:
  320:     case OPT_SIZE:
  321:         list->value.n = value;
  322:         break;
  323: 
  324:     default:
  325:         return -1;
  326:     }
  327: 
  328:     return 0;
  329: }
  330: 
  331: /*
  332:  * Frees a option list. If it contains strings, the strings are freed as well.
  333:  */
  334: void free_option_parameters(QEMUOptionParameter *list)
  335: {
  336:     QEMUOptionParameter *cur = list;
  337: 
  338:     while (cur && cur->name) {
  339:         if (cur->type == OPT_STRING) {
  340:             g_free(cur->value.s);
  341:         }
  342:         cur++;
  343:     }
  344: 
  345:     g_free(list);
  346: }
  347: 
  348: /*
  349:  * Count valid options in list
  350:  */
  351: static size_t count_option_parameters(QEMUOptionParameter *list)
  352: {
  353:     size_t num_options = 0;
  354: 
  355:     while (list && list->name) {
  356:         num_options++;
  357:         list++;
  358:     }
  359: 
  360:     return num_options;
  361: }
  362: 
  363: /*
  364:  * Append an option list (list) to an option list (dest).
  365:  *
  366:  * If dest is NULL, a new copy of list is created.
  367:  *
  368:  * Returns a pointer to the first element of dest (or the newly allocated copy)
  369:  */
  370: QEMUOptionParameter *append_option_parameters(QEMUOptionParameter *dest,
  371:     QEMUOptionParameter *list)
  372: {
  373:     size_t num_options, num_dest_options;
  374: 
  375:     num_options = count_option_parameters(dest);
  376:     num_dest_options = num_options;
  377: 
  378:     num_options += count_option_parameters(list);
  379: 
  380:     dest = g_realloc(dest, (num_options + 1) * sizeof(QEMUOptionParameter));
  381:     dest[num_dest_options].name = NULL;
  382: 
  383:     while (list && list->name) {
  384:         if (get_option_parameter(dest, list->name) == NULL) {
  385:             dest[num_dest_options++] = *list;
  386:             dest[num_dest_options].name = NULL;
  387:         }
  388:         list++;
  389:     }
  390: 
  391:     return dest;
  392: }
  393: 
  394: /*
  395:  * Parses a parameter string (param) into an option list (dest).
  396:  *
  397:  * list is the template option list. If dest is NULL, a new copy of list is
  398:  * created. If list is NULL, this function fails.
  399:  *
  400:  * A parameter string consists of one or more parameters, separated by commas.
  401:  * Each parameter consists of its name and possibly of a value. In the latter
  402:  * case, the value is delimited by an = character. To specify a value which
  403:  * contains commas, double each comma so it won't be recognized as the end of
  404:  * the parameter.
  405:  *
  406:  * For more details of the parsing see above.
  407:  *
  408:  * Returns a pointer to the first element of dest (or the newly allocated copy)
  409:  * or NULL in error cases
  410:  */
  411: QEMUOptionParameter *parse_option_parameters(const char *param,
  412:     QEMUOptionParameter *list, QEMUOptionParameter *dest)
  413: {
  414:     QEMUOptionParameter *allocated = NULL;
  415:     char name[256];
  416:     char value[256];
  417:     char *param_delim, *value_delim;
  418:     char next_delim;
  419: 
  420:     if (list == NULL) {
  421:         return NULL;
  422:     }
  423: 
  424:     if (dest == NULL) {
  425:         dest = allocated = append_option_parameters(NULL, list);
  426:     }
  427: 
  428:     while (*param) {
  429: 
  430:         // Find parameter name and value in the string
  431:         param_delim = strchr(param, ',');
  432:         value_delim = strchr(param, '=');
  433: 
  434:         if (value_delim && (value_delim < param_delim || !param_delim)) {
  435:             next_delim = '=';
  436:         } else {
  437:             next_delim = ',';
  438:             value_delim = NULL;
  439:         }
  440: 
  441:         param = get_opt_name(name, sizeof(name), param, next_delim);
  442:         if (value_delim) {
  443:             param = get_opt_value(value, sizeof(value), param + 1);
  444:         }
  445:         if (*param != '\0') {
  446:             param++;
  447:         }
  448: 
  449:         // Set the parameter
  450:         if (set_option_parameter(dest, name, value_delim ? value : NULL)) {
  451:             goto fail;
  452:         }
  453:     }
  454: 
  455:     return dest;
  456: 
  457: fail:
  458:     // Only free the list if it was newly allocated
  459:     free_option_parameters(allocated);
  460:     return NULL;
  461: }
  462: 
  463: /*
  464:  * Prints all options of a list that have a value to stdout
  465:  */
  466: void print_option_parameters(QEMUOptionParameter *list)
  467: {
  468:     while (list && list->name) {
  469:         switch (list->type) {
  470:             case OPT_STRING:
  471:                  if (list->value.s != NULL) {
  472:                      printf("%s='%s' ", list->name, list->value.s);
  473:                  }
  474:                 break;
  475:             case OPT_FLAG:
  476:                 printf("%s=%s ", list->name, list->value.n ? "on" : "off");
  477:                 break;
  478:             case OPT_SIZE:
  479:             case OPT_NUMBER:
  480:                 printf("%s=%" PRId64 " ", list->name, list->value.n);
  481:                 break;
  482:             default:
  483:                 printf("%s=(unkown type) ", list->name);
  484:                 break;
  485:         }
  486:         list++;
  487:     }
  488: }
  489: 
  490: /*
  491:  * Prints an overview of all available options
  492:  */
  493: void print_option_help(QEMUOptionParameter *list)
  494: {
  495:     printf("Supported options:\n");
  496:     while (list && list->name) {
  497:         printf("%-16s %s\n", list->name,
  498:             list->help ? list->help : "No description available");
  499:         list++;
  500:     }
  501: }
  502: 
  503: /* ------------------------------------------------------------------ */
  504: 
  505: struct QemuOpt {
  506:     const char   *name;
  507:     const char   *str;
  508: 
  509:     const QemuOptDesc *desc;
  510:     union {
  511:         bool boolean;
  512:         uint64_t uint;
  513:     } value;
  514: 
  515:     QemuOpts     *opts;
  516:     QTAILQ_ENTRY(QemuOpt) next;
  517: };
  518: 
  519: struct QemuOpts {
  520:     char *id;
  521:     QemuOptsList *list;
  522:     Location loc;
  523:     QTAILQ_HEAD(QemuOptHead, QemuOpt) head;
  524:     QTAILQ_ENTRY(QemuOpts) next;
  525: };
  526: 
  527: static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
  528: {
  529:     QemuOpt *opt;
  530: 
  531:     QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
  532:         if (strcmp(opt->name, name) != 0)
  533:             continue;
  534:         return opt;
  535:     }
  536:     return NULL;
  537: }
  538: 
  539: const char *qemu_opt_get(QemuOpts *opts, const char *name)
  540: {
  541:     QemuOpt *opt = qemu_opt_find(opts, name);
  542:     return opt ? opt->str : NULL;
  543: }
  544: 
  545: bool qemu_opt_get_bool(QemuOpts *opts, const char *name, bool defval)
  546: {
  547:     QemuOpt *opt = qemu_opt_find(opts, name);
  548: 
  549:     if (opt == NULL)
  550:         return defval;
  551:     assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
  552:     return opt->value.boolean;
  553: }
  554: 
  555: uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
  556: {
  557:     QemuOpt *opt = qemu_opt_find(opts, name);
  558: 
  559:     if (opt == NULL)
  560:         return defval;
  561:     assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
  562:     return opt->value.uint;
  563: }
  564: 
  565: uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
  566: {
  567:     QemuOpt *opt = qemu_opt_find(opts, name);
  568: 
  569:     if (opt == NULL)
  570:         return defval;
  571:     assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
  572:     return opt->value.uint;
  573: }
  574: 
  575: static int qemu_opt_parse(QemuOpt *opt)
  576: {
  577:     if (opt->desc == NULL)
  578:         return 0;
  579:     switch (opt->desc->type) {
  580:     case QEMU_OPT_STRING:
  581:         /* nothing */
  582:         return 0;
  583:     case QEMU_OPT_BOOL:
  584:         return parse_option_bool(opt->name, opt->str, &opt->value.boolean);
  585:     case QEMU_OPT_NUMBER:
  586:         return parse_option_number(opt->name, opt->str, &opt->value.uint);
  587:     case QEMU_OPT_SIZE:
  588:         return parse_option_size(opt->name, opt->str, &opt->value.uint);
  589:     default:
  590:         abort();
  591:     }
  592: }
  593: 
  594: static void qemu_opt_del(QemuOpt *opt)
  595: {
  596:     QTAILQ_REMOVE(&opt->opts->head, opt, next);
  597:     g_free((/* !const */ char*)opt->name);
  598:     g_free((/* !const */ char*)opt->str);
  599:     g_free(opt);
  600: }
  601: 
  602: int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
  603: {
  604:     QemuOpt *opt;
  605:     const QemuOptDesc *desc = opts->list->desc;
  606:     int i;
  607: 
  608:     for (i = 0; desc[i].name != NULL; i++) {
  609:         if (strcmp(desc[i].name, name) == 0) {
  610:             break;
  611:         }
  612:     }
  613:     if (desc[i].name == NULL) {
  614:         if (i == 0) {
  615:             /* empty list -> allow any */;
  616:         } else {
  617:             qerror_report(QERR_INVALID_PARAMETER, name);
  618:             return -1;
  619:         }
  620:     }
  621: 
  622:     opt = g_malloc0(sizeof(*opt));
  623:     opt->name = g_strdup(name);
  624:     opt->opts = opts;
  625:     QTAILQ_INSERT_TAIL(&opts->head, opt, next);
  626:     if (desc[i].name != NULL) {
  627:         opt->desc = desc+i;
  628:     }
  629:     if (value) {
  630:         opt->str = g_strdup(value);
  631:     }
  632:     if (qemu_opt_parse(opt) < 0) {
  633:         qemu_opt_del(opt);
  634:         return -1;
  635:     }
  636:     return 0;
  637: }
  638: 
  639: int qemu_opt_set_bool(QemuOpts *opts, const char *name, bool val)
  640: {
  641:     QemuOpt *opt;
  642:     const QemuOptDesc *desc = opts->list->desc;
  643:     int i;
  644: 
  645:     for (i = 0; desc[i].name != NULL; i++) {
  646:         if (strcmp(desc[i].name, name) == 0) {
  647:             break;
  648:         }
  649:     }
  650:     if (desc[i].name == NULL) {
  651:         if (i == 0) {
  652:             /* empty list -> allow any */;
  653:         } else {
  654:             qerror_report(QERR_INVALID_PARAMETER, name);
  655:             return -1;
  656:         }
  657:     }
  658: 
  659:     opt = g_malloc0(sizeof(*opt));
  660:     opt->name = g_strdup(name);
  661:     opt->opts = opts;
  662:     QTAILQ_INSERT_TAIL(&opts->head, opt, next);
  663:     if (desc[i].name != NULL) {
  664:         opt->desc = desc+i;
  665:     }
  666:     opt->value.boolean = !!val;
  667:     return 0;
  668: }
  669: 
  670: int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
  671:                      int abort_on_failure)
  672: {
  673:     QemuOpt *opt;
  674:     int rc = 0;
  675: 
  676:     QTAILQ_FOREACH(opt, &opts->head, next) {
  677:         rc = func(opt->name, opt->str, opaque);
  678:         if (abort_on_failure  &&  rc != 0)
  679:             break;
  680:     }
  681:     return rc;
  682: }
  683: 
  684: QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
  685: {
  686:     QemuOpts *opts;
  687: 
  688:     QTAILQ_FOREACH(opts, &list->head, next) {
  689:         if (!opts->id) {
  690:             continue;
  691:         }
  692:         if (strcmp(opts->id, id) != 0) {
  693:             continue;
  694:         }
  695:         return opts;
  696:     }
  697:     return NULL;
  698: }
  699: 
  700: static int id_wellformed(const char *id)
  701: {
  702:     int i;
  703: 
  704:     if (!qemu_isalpha(id[0])) {
  705:         return 0;
  706:     }
  707:     for (i = 1; id[i]; i++) {
  708:         if (!qemu_isalnum(id[i]) && !strchr("-._", id[i])) {
  709:             return 0;
  710:         }
  711:     }
  712:     return 1;
  713: }
  714: 
  715: QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists)
  716: {
  717:     QemuOpts *opts = NULL;
  718: 
  719:     if (id) {
  720:         if (!id_wellformed(id)) {
  721:             qerror_report(QERR_INVALID_PARAMETER_VALUE, "id", "an identifier");
  722:             error_printf_unless_qmp("Identifiers consist of letters, digits, '-', '.', '_', starting with a letter.\n");
  723:             return NULL;
  724:         }
  725:         opts = qemu_opts_find(list, id);
  726:         if (opts != NULL) {
  727:             if (fail_if_exists) {
  728:                 qerror_report(QERR_DUPLICATE_ID, id, list->name);
  729:                 return NULL;
  730:             } else {
  731:                 return opts;
  732:             }
  733:         }
  734:     }
  735:     opts = g_malloc0(sizeof(*opts));
  736:     if (id) {
  737:         opts->id = g_strdup(id);
  738:     }
  739:     opts->list = list;
  740:     loc_save(&opts->loc);
  741:     QTAILQ_INIT(&opts->head);
  742:     QTAILQ_INSERT_TAIL(&list->head, opts, next);
  743:     return opts;
  744: }
  745: 
  746: void qemu_opts_reset(QemuOptsList *list)
  747: {
  748:     QemuOpts *opts, *next_opts;
  749: 
  750:     QTAILQ_FOREACH_SAFE(opts, &list->head, next, next_opts) {
  751:         qemu_opts_del(opts);
  752:     }
  753: }
  754: 
  755: void qemu_opts_loc_restore(QemuOpts *opts)
  756: {
  757:     loc_restore(&opts->loc);
  758: }
  759: 
  760: int qemu_opts_set(QemuOptsList *list, const char *id,
  761:                   const char *name, const char *value)
  762: {
  763:     QemuOpts *opts;
  764: 
  765:     opts = qemu_opts_create(list, id, 1);
  766:     if (opts == NULL) {
  767:         return -1;
  768:     }
  769:     return qemu_opt_set(opts, name, value);
  770: }
  771: 
  772: const char *qemu_opts_id(QemuOpts *opts)
  773: {
  774:     return opts->id;
  775: }
  776: 
  777: void qemu_opts_del(QemuOpts *opts)
  778: {
  779:     QemuOpt *opt;
  780: 
  781:     for (;;) {
  782:         opt = QTAILQ_FIRST(&opts->head);
  783:         if (opt == NULL)
  784:             break;
  785:         qemu_opt_del(opt);
  786:     }
  787:     QTAILQ_REMOVE(&opts->list->head, opts, next);
  788:     g_free(opts->id);
  789:     g_free(opts);
  790: }
  791: 
  792: int qemu_opts_print(QemuOpts *opts, void *dummy)
  793: {
  794:     QemuOpt *opt;
  795: 
  796:     fprintf(stderr, "%s: %s:", opts->list->name,
  797:             opts->id ? opts->id : "<noid>");
  798:     QTAILQ_FOREACH(opt, &opts->head, next) {
  799:         fprintf(stderr, " %s=\"%s\"", opt->name, opt->str);
  800:     }
  801:     fprintf(stderr, "\n");
  802:     return 0;
  803: }
  804: 
  805: int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
  806: {
  807:     char option[128], value[1024];
  808:     const char *p,*pe,*pc;
  809: 
  810:     for (p = params; *p != '\0'; p++) {
  811:         pe = strchr(p, '=');
  812:         pc = strchr(p, ',');
  813:         if (!pe || (pc && pc < pe)) {
  814:             /* found "foo,more" */
  815:             if (p == params && firstname) {
  816:                 /* implicitly named first option */
  817:                 pstrcpy(option, sizeof(option), firstname);
  818:                 p = get_opt_value(value, sizeof(value), p);
  819:             } else {
  820:                 /* option without value, probably a flag */
  821:                 p = get_opt_name(option, sizeof(option), p, ',');
  822:                 if (strncmp(option, "no", 2) == 0) {
  823:                     memmove(option, option+2, strlen(option+2)+1);
  824:                     pstrcpy(value, sizeof(value), "off");
  825:                 } else {
  826:                     pstrcpy(value, sizeof(value), "on");
  827:                 }
  828:             }
  829:         } else {
  830:             /* found "foo=bar,more" */
  831:             p = get_opt_name(option, sizeof(option), p, '=');
  832:             if (*p != '=') {
  833:                 break;
  834:             }
  835:             p++;
  836:             p = get_opt_value(value, sizeof(value), p);
  837:         }
  838:         if (strcmp(option, "id") != 0) {
  839:             /* store and parse */
  840:             if (qemu_opt_set(opts, option, value) == -1) {
  841:                 return -1;
  842:             }
  843:         }
  844:         if (*p != ',') {
  845:             break;
  846:         }
  847:     }
  848:     return 0;
  849: }
  850: 
  851: QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params,
  852:                           int permit_abbrev)
  853: {
  854:     const char *firstname;
  855:     char value[1024], *id = NULL;
  856:     const char *p;
  857:     QemuOpts *opts;
  858: 
  859:     assert(!permit_abbrev || list->implied_opt_name);
  860:     firstname = permit_abbrev ? list->implied_opt_name : NULL;
  861: 
  862:     if (strncmp(params, "id=", 3) == 0) {
  863:         get_opt_value(value, sizeof(value), params+3);
  864:         id = value;
  865:     } else if ((p = strstr(params, ",id=")) != NULL) {
  866:         get_opt_value(value, sizeof(value), p+4);
  867:         id = value;
  868:     }
  869:     opts = qemu_opts_create(list, id, 1);
  870:     if (opts == NULL)
  871:         return NULL;
  872: 
  873:     if (qemu_opts_do_parse(opts, params, firstname) != 0) {
  874:         qemu_opts_del(opts);
  875:         return NULL;
  876:     }
  877: 
  878:     return opts;
  879: }
  880: 
  881: static void qemu_opts_from_qdict_1(const char *key, QObject *obj, void *opaque)
  882: {
  883:     char buf[32];
  884:     const char *value;
  885:     int n;
  886: 
  887:     if (!strcmp(key, "id")) {
  888:         return;
  889:     }
  890: 
  891:     switch (qobject_type(obj)) {
  892:     case QTYPE_QSTRING:
  893:         value = qstring_get_str(qobject_to_qstring(obj));
  894:         break;
  895:     case QTYPE_QINT:
  896:         n = snprintf(buf, sizeof(buf), "%" PRId64,
  897:                      qint_get_int(qobject_to_qint(obj)));
  898:         assert(n < sizeof(buf));
  899:         value = buf;
  900:         break;
  901:     case QTYPE_QFLOAT:
  902:         n = snprintf(buf, sizeof(buf), "%.17g",
  903:                      qfloat_get_double(qobject_to_qfloat(obj)));
  904:         assert(n < sizeof(buf));
  905:         value = buf;
  906:         break;
  907:     case QTYPE_QBOOL:
  908:         pstrcpy(buf, sizeof(buf),
  909:                 qbool_get_int(qobject_to_qbool(obj)) ? "on" : "off");
  910:         value = buf;
  911:         break;
  912:     default:
  913:         return;
  914:     }
  915:     qemu_opt_set(opaque, key, value);
  916: }
  917: 
  918: /*
  919:  * Create QemuOpts from a QDict.
  920:  * Use value of key "id" as ID if it exists and is a QString.
  921:  * Only QStrings, QInts, QFloats and QBools are copied.  Entries with
  922:  * other types are silently ignored.
  923:  */
  924: QemuOpts *qemu_opts_from_qdict(QemuOptsList *list, const QDict *qdict)
  925: {
  926:     QemuOpts *opts;
  927: 
  928:     opts = qemu_opts_create(list, qdict_get_try_str(qdict, "id"), 1);
  929:     if (opts == NULL)
  930:         return NULL;
  931: 
  932:     qdict_iter(qdict, qemu_opts_from_qdict_1, opts);
  933:     return opts;
  934: }
  935: 
  936: /*
  937:  * Convert from QemuOpts to QDict.
  938:  * The QDict values are of type QString.
  939:  * TODO We'll want to use types appropriate for opt->desc->type, but
  940:  * this is enough for now.
  941:  */
  942: QDict *qemu_opts_to_qdict(QemuOpts *opts, QDict *qdict)
  943: {
  944:     QemuOpt *opt;
  945:     QObject *val;
  946: 
  947:     if (!qdict) {
  948:         qdict = qdict_new();
  949:     }
  950:     if (opts->id) {
  951:         qdict_put(qdict, "id", qstring_from_str(opts->id));
  952:     }
  953:     QTAILQ_FOREACH(opt, &opts->head, next) {
  954:         val = QOBJECT(qstring_from_str(opt->str));
  955:         qdict_put_obj(qdict, opt->name, val);
  956:     }
  957:     return qdict;
  958: }
  959: 
  960: /* Validate parsed opts against descriptions where no
  961:  * descriptions were provided in the QemuOptsList.
  962:  */
  963: int qemu_opts_validate(QemuOpts *opts, const QemuOptDesc *desc)
  964: {
  965:     QemuOpt *opt;
  966: 
  967:     assert(opts->list->desc[0].name == NULL);
  968: 
  969:     QTAILQ_FOREACH(opt, &opts->head, next) {
  970:         int i;
  971: 
  972:         for (i = 0; desc[i].name != NULL; i++) {
  973:             if (strcmp(desc[i].name, opt->name) == 0) {
  974:                 break;
  975:             }
  976:         }
  977:         if (desc[i].name == NULL) {
  978:             qerror_report(QERR_INVALID_PARAMETER, opt->name);
  979:             return -1;
  980:         }
  981: 
  982:         opt->desc = &desc[i];
  983: 
  984:         if (qemu_opt_parse(opt) < 0) {
  985:             return -1;
  986:         }
  987:     }
  988: 
  989:     return 0;
  990: }
  991: 
  992: int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque,
  993:                       int abort_on_failure)
  994: {
  995:     Location loc;
  996:     QemuOpts *opts;
  997:     int rc = 0;
  998: 
  999:     loc_push_none(&loc);
 1000:     QTAILQ_FOREACH(opts, &list->head, next) {
 1001:         loc_restore(&opts->loc);
 1002:         rc |= func(opts, opaque);
 1003:         if (abort_on_failure  &&  rc != 0)
 1004:             break;
 1005:     }
 1006:     loc_pop(&loc);
 1007:     return rc;
 1008: }

unix.superglobalmegacorp.com