Diff for /qemu/qemu-option.c between versions 1.1.1.1 and 1.1.1.2

version 1.1.1.1, 2018/04/24 17:20:12 version 1.1.1.2, 2018/04/24 17:33:36
Line 85  const char *get_opt_value(char *buf, int Line 85  const char *get_opt_value(char *buf, int
     return p;      return p;
 }  }
   
   int get_next_param_value(char *buf, int buf_size,
                            const char *tag, const char **pstr)
   {
       const char *p;
       char option[128];
   
       p = *pstr;
       for(;;) {
           p = get_opt_name(option, sizeof(option), p, '=');
           if (*p != '=')
               break;
           p++;
           if (!strcmp(tag, option)) {
               *pstr = get_opt_value(buf, buf_size, p);
               if (**pstr == ',') {
                   (*pstr)++;
               }
               return strlen(buf);
           } else {
               p = get_opt_value(NULL, 0, p);
           }
           if (*p != ',')
               break;
           p++;
       }
       return 0;
   }
   
   int get_param_value(char *buf, int buf_size,
                       const char *tag, const char *str)
   {
       return get_next_param_value(buf, buf_size, tag, &str);
   }
   
   int check_params(char *buf, int buf_size,
                    const char * const *params, const char *str)
   {
       const char *p;
       int i;
   
       p = str;
       while (*p != '\0') {
           p = get_opt_name(buf, buf_size, p, '=');
           if (*p != '=') {
               return -1;
           }
           p++;
           for (i = 0; params[i] != NULL; i++) {
               if (!strcmp(params[i], buf)) {
                   break;
               }
           }
           if (params[i] == NULL) {
               return -1;
           }
           p = get_opt_value(NULL, 0, p);
           if (*p != ',') {
               break;
           }
           p++;
       }
       return 0;
   }
   
 /*  /*
  * Searches an option list for an option with the given name   * Searches an option list for an option with the given name
  */   */
Line 101  QEMUOptionParameter *get_option_paramete Line 165  QEMUOptionParameter *get_option_paramete
     return NULL;      return NULL;
 }  }
   
   static int parse_option_bool(const char *name, const char *value, int *ret)
   {
       if (value != NULL) {
           if (!strcmp(value, "on")) {
               *ret = 1;
           } else if (!strcmp(value, "off")) {
               *ret = 0;
           } else {
               fprintf(stderr, "Option '%s': Use 'on' or 'off'\n", name);
               return -1;
           }
       } else {
           *ret = 1;
       }
       return 0;
   }
   
   static int parse_option_number(const char *name, const char *value, uint64_t *ret)
   {
       char *postfix;
       uint64_t number;
   
       if (value != NULL) {
           number = strtoull(value, &postfix, 0);
           if (*postfix != '\0') {
               fprintf(stderr, "Option '%s' needs a number as parameter\n", name);
               return -1;
           }
           *ret = number;
       } else {
           fprintf(stderr, "Option '%s' needs a parameter\n", name);
           return -1;
       }
       return 0;
   }
   
   static int parse_option_size(const char *name, const char *value, uint64_t *ret)
   {
       char *postfix;
       double sizef;
   
       if (value != NULL) {
           sizef = strtod(value, &postfix);
           switch (*postfix) {
           case 'T':
               sizef *= 1024;
           case 'G':
               sizef *= 1024;
           case 'M':
               sizef *= 1024;
           case 'K':
           case 'k':
               sizef *= 1024;
           case 'b':
           case '\0':
               *ret = (uint64_t) sizef;
               break;
           default:
               fprintf(stderr, "Option '%s' needs size as parameter\n", name);
               fprintf(stderr, "You may use k, M, G or T suffixes for "
                       "kilobytes, megabytes, gigabytes and terabytes.\n");
               return -1;
           }
       } else {
           fprintf(stderr, "Option '%s' needs a parameter\n", name);
           return -1;
       }
       return 0;
   }
   
 /*  /*
  * Sets the value of a parameter in a given option list. The parsing of the   * Sets the value of a parameter in a given option list. The parsing of the
  * value depends on the type of option:   * value depends on the type of option:
Line 121  QEMUOptionParameter *get_option_paramete Line 255  QEMUOptionParameter *get_option_paramete
 int set_option_parameter(QEMUOptionParameter *list, const char *name,  int set_option_parameter(QEMUOptionParameter *list, const char *name,
     const char *value)      const char *value)
 {  {
       int flag;
   
     // Find a matching parameter      // Find a matching parameter
     list = get_option_parameter(list, name);      list = get_option_parameter(list, name);
     if (list == NULL) {      if (list == NULL) {
Line 131  int set_option_parameter(QEMUOptionParam Line 267  int set_option_parameter(QEMUOptionParam
     // Process parameter      // Process parameter
     switch (list->type) {      switch (list->type) {
     case OPT_FLAG:      case OPT_FLAG:
         if (value != NULL) {          if (parse_option_bool(name, value, &flag) == -1)
             if (!strcmp(value, "on")) {              return -1;
                 list->value.n = 1;          list->value.n = flag;
             } else if (!strcmp(value, "off")) {  
                 list->value.n = 0;  
             } else {  
                 fprintf(stderr, "Option '%s': Use 'on' or 'off'\n", name);  
                 return -1;  
             }  
         } else {  
             list->value.n = 1;  
         }  
         break;          break;
   
     case OPT_STRING:      case OPT_STRING:
         if (value != NULL) {          if (value != NULL) {
             list->value.s = strdup(value);              list->value.s = qemu_strdup(value);
         } else {          } else {
             fprintf(stderr, "Option '%s' needs a parameter\n", name);              fprintf(stderr, "Option '%s' needs a parameter\n", name);
             return -1;              return -1;
Line 155  int set_option_parameter(QEMUOptionParam Line 282  int set_option_parameter(QEMUOptionParam
         break;          break;
   
     case OPT_SIZE:      case OPT_SIZE:
         if (value != NULL) {          if (parse_option_size(name, value, &list->value.n) == -1)
             double sizef = strtod(value, (char**) &value);  
   
             switch (*value) {  
             case 'T':  
                 sizef *= 1024;  
             case 'G':  
                 sizef *= 1024;  
             case 'M':  
                 sizef *= 1024;  
             case 'K':  
             case 'k':  
                 sizef *= 1024;  
             case 'b':  
             case '\0':  
                 list->value.n = (uint64_t) sizef;  
                 break;  
             default:  
                 fprintf(stderr, "Option '%s' needs size as parameter\n", name);  
                 fprintf(stderr, "You may use k, M, G or T suffixes for "  
                     "kilobytes, megabytes, gigabytes and terabytes.\n");  
                 return -1;  
             }  
         } else {  
             fprintf(stderr, "Option '%s' needs a parameter\n", name);  
             return -1;              return -1;
         }  
         break;          break;
   
     default:      default:
         fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);          fprintf(stderr, "Bug: Option '%s' has an unknown type\n", name);
         return -1;          return -1;
Line 231  void free_option_parameters(QEMUOptionPa Line 334  void free_option_parameters(QEMUOptionPa
   
     while (cur && cur->name) {      while (cur && cur->name) {
         if (cur->type == OPT_STRING) {          if (cur->type == OPT_STRING) {
             free(cur->value.s);              qemu_free(cur->value.s);
         }          }
         cur++;          cur++;
     }      }
   
     free(list);      qemu_free(list);
 }  }
   
 /*  /*
Line 360  void print_option_help(QEMUOptionParamet Line 463  void print_option_help(QEMUOptionParamet
         list++;          list++;
     }      }
 }  }
   
   /* ------------------------------------------------------------------ */
   
   struct QemuOpt {
       const char   *name;
       const char   *str;
   
       QemuOptDesc  *desc;
       union {
           int      boolean;
           uint64_t uint;
       } value;
   
       QemuOpts     *opts;
       QTAILQ_ENTRY(QemuOpt) next;
   };
   
   struct QemuOpts {
       char *id;
       QemuOptsList *list;
       QTAILQ_HEAD(QemuOptHead, QemuOpt) head;
       QTAILQ_ENTRY(QemuOpts) next;
   };
   
   static QemuOpt *qemu_opt_find(QemuOpts *opts, const char *name)
   {
       QemuOpt *opt;
   
       QTAILQ_FOREACH_REVERSE(opt, &opts->head, QemuOptHead, next) {
           if (strcmp(opt->name, name) != 0)
               continue;
           return opt;
       }
       return NULL;
   }
   
   const char *qemu_opt_get(QemuOpts *opts, const char *name)
   {
       QemuOpt *opt = qemu_opt_find(opts, name);
       return opt ? opt->str : NULL;
   }
   
   int qemu_opt_get_bool(QemuOpts *opts, const char *name, int defval)
   {
       QemuOpt *opt = qemu_opt_find(opts, name);
   
       if (opt == NULL)
           return defval;
       assert(opt->desc && opt->desc->type == QEMU_OPT_BOOL);
       return opt->value.boolean;
   }
   
   uint64_t qemu_opt_get_number(QemuOpts *opts, const char *name, uint64_t defval)
   {
       QemuOpt *opt = qemu_opt_find(opts, name);
   
       if (opt == NULL)
           return defval;
       assert(opt->desc && opt->desc->type == QEMU_OPT_NUMBER);
       return opt->value.uint;
   }
   
   uint64_t qemu_opt_get_size(QemuOpts *opts, const char *name, uint64_t defval)
   {
       QemuOpt *opt = qemu_opt_find(opts, name);
   
       if (opt == NULL)
           return defval;
       assert(opt->desc && opt->desc->type == QEMU_OPT_SIZE);
       return opt->value.uint;
   }
   
   static int qemu_opt_parse(QemuOpt *opt)
   {
       if (opt->desc == NULL)
           return 0;
       switch (opt->desc->type) {
       case QEMU_OPT_STRING:
           /* nothing */
           return 0;
       case QEMU_OPT_BOOL:
           return parse_option_bool(opt->name, opt->str, &opt->value.boolean);
       case QEMU_OPT_NUMBER:
           return parse_option_number(opt->name, opt->str, &opt->value.uint);
       case QEMU_OPT_SIZE:
           return parse_option_size(opt->name, opt->str, &opt->value.uint);
       default:
           abort();
       }
   }
   
   static void qemu_opt_del(QemuOpt *opt)
   {
       QTAILQ_REMOVE(&opt->opts->head, opt, next);
       qemu_free((/* !const */ char*)opt->name);
       qemu_free((/* !const */ char*)opt->str);
       qemu_free(opt);
   }
   
   int qemu_opt_set(QemuOpts *opts, const char *name, const char *value)
   {
       QemuOpt *opt;
       QemuOptDesc *desc = opts->list->desc;
       int i;
   
       for (i = 0; desc[i].name != NULL; i++) {
           if (strcmp(desc[i].name, name) == 0) {
               break;
           }
       }
       if (desc[i].name == NULL) {
           if (i == 0) {
               /* empty list -> allow any */;
           } else {
               fprintf(stderr, "option \"%s\" is not valid for %s\n",
                       name, opts->list->name);
               return -1;
           }
       }
   
       opt = qemu_mallocz(sizeof(*opt));
       opt->name = qemu_strdup(name);
       opt->opts = opts;
       QTAILQ_INSERT_TAIL(&opts->head, opt, next);
       if (desc[i].name != NULL) {
           opt->desc = desc+i;
       }
       if (value) {
           opt->str = qemu_strdup(value);
       }
       if (qemu_opt_parse(opt) < 0) {
           fprintf(stderr, "Failed to parse \"%s\" for \"%s.%s\"\n", opt->str,
                   opts->list->name, opt->name);
           qemu_opt_del(opt);
           return -1;
       }
       return 0;
   }
   
   int qemu_opt_foreach(QemuOpts *opts, qemu_opt_loopfunc func, void *opaque,
                        int abort_on_failure)
   {
       QemuOpt *opt;
       int rc = 0;
   
       QTAILQ_FOREACH(opt, &opts->head, next) {
           rc = func(opt->name, opt->str, opaque);
           if (abort_on_failure  &&  rc != 0)
               break;
       }
       return rc;
   }
   
   QemuOpts *qemu_opts_find(QemuOptsList *list, const char *id)
   {
       QemuOpts *opts;
   
       QTAILQ_FOREACH(opts, &list->head, next) {
           if (!opts->id) {
               continue;
           }
           if (strcmp(opts->id, id) != 0) {
               continue;
           }
           return opts;
       }
       return NULL;
   }
   
   QemuOpts *qemu_opts_create(QemuOptsList *list, const char *id, int fail_if_exists)
   {
       QemuOpts *opts = NULL;
   
       if (id) {
           opts = qemu_opts_find(list, id);
           if (opts != NULL) {
               if (fail_if_exists) {
                   fprintf(stderr, "tried to create id \"%s\" twice for \"%s\"\n",
                           id, list->name);
                   return NULL;
               } else {
                   return opts;
               }
           }
       }
       opts = qemu_mallocz(sizeof(*opts));
       if (id) {
           opts->id = qemu_strdup(id);
       }
       opts->list = list;
       QTAILQ_INIT(&opts->head);
       QTAILQ_INSERT_TAIL(&list->head, opts, next);
       return opts;
   }
   
   int qemu_opts_set(QemuOptsList *list, const char *id,
                     const char *name, const char *value)
   {
       QemuOpts *opts;
   
       opts = qemu_opts_create(list, id, 1);
       if (opts == NULL) {
           return -1;
       }
       return qemu_opt_set(opts, name, value);
   }
   
   const char *qemu_opts_id(QemuOpts *opts)
   {
       return opts->id;
   }
   
   void qemu_opts_del(QemuOpts *opts)
   {
       QemuOpt *opt;
   
       for (;;) {
           opt = QTAILQ_FIRST(&opts->head);
           if (opt == NULL)
               break;
           qemu_opt_del(opt);
       }
       QTAILQ_REMOVE(&opts->list->head, opts, next);
       qemu_free(opts->id);
       qemu_free(opts);
   }
   
   int qemu_opts_print(QemuOpts *opts, void *dummy)
   {
       QemuOpt *opt;
   
       fprintf(stderr, "%s: %s:", opts->list->name,
               opts->id ? opts->id : "<noid>");
       QTAILQ_FOREACH(opt, &opts->head, next) {
           fprintf(stderr, " %s=\"%s\"", opt->name, opt->str);
       }
       fprintf(stderr, "\n");
       return 0;
   }
   
   int qemu_opts_do_parse(QemuOpts *opts, const char *params, const char *firstname)
   {
       char option[128], value[1024];
       const char *p,*pe,*pc;
   
       for (p = params; *p != '\0'; p++) {
           pe = strchr(p, '=');
           pc = strchr(p, ',');
           if (!pe || (pc && pc < pe)) {
               /* found "foo,more" */
               if (p == params && firstname) {
                   /* implicitly named first option */
                   pstrcpy(option, sizeof(option), firstname);
                   p = get_opt_value(value, sizeof(value), p);
               } else {
                   /* option without value, probably a flag */
                   p = get_opt_name(option, sizeof(option), p, ',');
                   if (strncmp(option, "no", 2) == 0) {
                       memmove(option, option+2, strlen(option+2)+1);
                       pstrcpy(value, sizeof(value), "off");
                   } else {
                       pstrcpy(value, sizeof(value), "on");
                   }
               }
           } else {
               /* found "foo=bar,more" */
               p = get_opt_name(option, sizeof(option), p, '=');
               if (*p != '=') {
                   break;
               }
               p++;
               p = get_opt_value(value, sizeof(value), p);
           }
           if (strcmp(option, "id") != 0) {
               /* store and parse */
               if (qemu_opt_set(opts, option, value) == -1) {
                   return -1;
               }
           }
           if (*p != ',') {
               break;
           }
       }
       return 0;
   }
   
   QemuOpts *qemu_opts_parse(QemuOptsList *list, const char *params, const char *firstname)
   {
       char value[1024], *id = NULL;
       const char *p;
       QemuOpts *opts;
   
       if (strncmp(params, "id=", 3) == 0) {
           get_opt_value(value, sizeof(value), params+3);
           id = qemu_strdup(value);
       } else if ((p = strstr(params, ",id=")) != NULL) {
           get_opt_value(value, sizeof(value), p+4);
           id = qemu_strdup(value);
       }
       opts = qemu_opts_create(list, id, 1);
       if (opts == NULL)
           return NULL;
   
       if (qemu_opts_do_parse(opts, params, firstname) != 0) {
           qemu_opts_del(opts);
           return NULL;
       }
   
       return opts;
   }
   
   /* Validate parsed opts against descriptions where no
    * descriptions were provided in the QemuOptsList.
    */
   int qemu_opts_validate(QemuOpts *opts, QemuOptDesc *desc)
   {
       QemuOpt *opt;
   
       assert(opts->list->desc[0].name == NULL);
   
       QTAILQ_FOREACH(opt, &opts->head, next) {
           int i;
   
           for (i = 0; desc[i].name != NULL; i++) {
               if (strcmp(desc[i].name, opt->name) == 0) {
                   break;
               }
           }
           if (desc[i].name == NULL) {
               fprintf(stderr, "option \"%s\" is not valid for %s\n",
                       opt->name, opts->list->name);
               return -1;
           }
   
           opt->desc = &desc[i];
   
           if (qemu_opt_parse(opt) < 0) {
               return -1;
           }
       }
   
       return 0;
   }
   
   int qemu_opts_foreach(QemuOptsList *list, qemu_opts_loopfunc func, void *opaque,
                         int abort_on_failure)
   {
       QemuOpts *opts;
       int rc = 0;
   
       QTAILQ_FOREACH(opts, &list->head, next) {
           rc = func(opts, opaque);
           if (abort_on_failure  &&  rc != 0)
               break;
       }
       return rc;
   }

Removed from v.1.1.1.1  
changed lines
  Added in v.1.1.1.2


unix.superglobalmegacorp.com