+static int parse_long(char *data, char **end, long *out) {
+ long result;
+ int savederr = errno;
+ char *myend;
+
+ errno = 0;
+ result = strtol(data, &myend, 10);
+ if (((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE)
+ || myend == data) {
+ errno = savederr;
+ return 0;
+ }
+
+ errno = savederr;
+ *out = result;
+ *end = myend;
+
+ return 1;
+}
+
+/* parse a comma-separated list of integers
+ returns when it has maxcount numbers, finds a non-comma after a number
+ or can't parse a number
+ if it can't parse a number after a comma, that's considered an error
+*/
+static int parse_long_list(char *data, char **end, int maxcount, long *out) {
+ int i;
+
+ i = 0;
+ while (i < maxcount-1) {
+ if (!parse_long(data, &data, out))
+ return 0;
+ out++;
+ i++;
+ if (*data != ',')
+ return i;
+ ++data;
+ }
+ if (!parse_long(data, &data, out))
+ return 0;
+ ++i;
+ *end = data;
+ return i;
+}
+
+/* parse "color(red,green,blue,alpha)" */
+static int parse_color(char *data, char **end, i_color *value) {
+ long n[4];
+ int count, i;
+
+ if (memcmp(data, "color(", 6))
+ return 0; /* not a color */
+ data += 6;
+ count = parse_long_list(data, &data, 4, n);
+ if (count < 3)
+ return 0;
+ for (i = 0; i < count; ++i)
+ value->channel[i] = n[i];
+ if (count < 4)
+ value->channel[3] = 255;
+
+ return 1;
+}
+
+/*
+=item i_tags_get_color(tags, name, code, &value)
+
+=category Tags
+
+Retrieve a tag specified by name or code as color.
+
+On success sets the i_color *I<value> to the color and returns true.
+
+On failure returns false.
+
+=cut
+*/
+
+int i_tags_get_color(i_img_tags *tags, char const *name, int code,
+ i_color *value) {
+ int index;
+ i_img_tag *entry;
+ char *end;
+
+ if (name) {
+ if (!i_tags_find(tags, name, 0, &index))
+ return 0;
+ }
+ else {
+ if (!i_tags_findn(tags, code, 0, &index))
+ return 0;
+ }
+ entry = tags->tags+index;
+ if (!entry->data)
+ return 0;
+
+ if (!parse_color(entry->data, &end, value))
+ return 0;
+
+ /* for now we're sloppy about the end */
+
+ return 1;
+}
+
+/*
+=item i_tags_set_color(tags, name, code, &value)
+
+=category Tags
+
+Stores the given color as a tag with the given name and code.
+
+=cut
+*/
+
+int i_tags_set_color(i_img_tags *tags, char const *name, int code,
+ i_color const *value) {
+ char temp[80];
+
+ sprintf(temp, "color(%d,%d,%d,%d)", value->channel[0], value->channel[1],
+ value->channel[2], value->channel[3]);
+ if (name)
+ i_tags_delbyname(tags, name);
+ else
+ i_tags_delbycode(tags, code);
+
+ return i_tags_add(tags, name, code, temp, strlen(temp), 0);
+}
+
+/*
+=item i_tags_get_string(tags, name, code, value, value_size)
+
+=category Tags
+
+Retrieves a tag by name or code as a string.
+
+On success copies the string to value for a max of value_size and
+returns true.
+
+On failure returns false.
+
+value_size must be at least large enough for a string representation
+of an integer.
+
+The copied value is always C<NUL> terminated.
+
+=cut
+*/
+
+int i_tags_get_string(i_img_tags *tags, char const *name, int code,