i_tags_delete(&tags, index);
count = i_tags_delbyname(tags, name);
count = i_tags_delbycode(tags, code);
+ if (i_tags_get_float(&tags, name, code, &float_value)) { found }
+ i_tags_set_float(&tags, name, code, value);
+ i_tags_set_float2(&tags, name, code, value, sig_digits);
+ i_tags_get_int(&tags, name, code, &int_value);
=head1 DESCRIPTION
=cut
*/
-#include "image.h"
+#include "imager.h"
#include <string.h>
#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
/* useful for debugging */
void i_tags_print(i_img_tags *tags);
/*
=item i_tags_new(i_img_tags *tags)
+=category Tags
+
Initialize a tags structure. Should not be used if the tags structure
has been previously used.
+This should be called tags member of an i_img object on creation (in
+i_img_*_new() functions).
+
To destroy the contents use i_tags_destroy()
=cut
=cut
*/
-int i_tags_addn(i_img_tags *tags, char *name, int code, int idata) {
+int i_tags_addn(i_img_tags *tags, char const *name, int code, int idata) {
return i_tags_add(tags, name, code, NULL, 0, idata);
}
=cut
*/
-int i_tags_add(i_img_tags *tags, char *name, int code, char *data, int size,
- int idata) {
+int i_tags_add(i_img_tags *tags, char const *name, int code, char const *data,
+ int size, int idata) {
i_img_tag work = {0};
+ /*printf("i_tags_add(tags %p [count %d], name %s, code %d, data %p, size %d, idata %d)\n",
+ tags, tags->count, name, code, data, size, idata);*/
if (tags->tags == NULL) {
int alloc = 10;
- tags->tags = malloc(sizeof(i_img_tag) * alloc);
+ tags->tags = mymalloc(sizeof(i_img_tag) * alloc);
if (!tags->tags)
return 0;
tags->alloc = alloc;
}
else if (tags->count == tags->alloc) {
int newalloc = tags->alloc + 10;
- void *newtags = realloc(tags->tags, sizeof(i_img_tag) * newalloc);
+ void *newtags = myrealloc(tags->tags, sizeof(i_img_tag) * newalloc);
if (!newtags) {
return 0;
}
tags->alloc = newalloc;
}
if (name) {
- work.name = malloc(strlen(name)+1);
+ work.name = mymalloc(strlen(name)+1);
if (!work.name)
return 0;
strcpy(work.name, name);
}
if (data) {
- work.data = malloc(size+1);
+ if (size == -1)
+ size = strlen(data);
+ work.data = mymalloc(size+1);
if (!work.data) {
- if (work.name) free(work.name);
+ if (work.name) myfree(work.name);
return 0;
}
memcpy(work.data, data, size);
work.idata = idata;
tags->tags[tags->count++] = work;
+ /*i_tags_print(tags);*/
+
return 1;
}
+/*
+=item i_tags_destroy(tags)
+
+=category Tags
+
+Destroys the given tags structure. Called by i_img_destroy().
+
+=cut
+*/
+
void i_tags_destroy(i_img_tags *tags) {
if (tags->tags) {
int i;
for (i = 0; i < tags->count; ++i) {
if (tags->tags[i].name)
- free(tags->tags[i].name);
+ myfree(tags->tags[i].name);
if (tags->tags[i].data)
- free(tags->tags[i].data);
+ myfree(tags->tags[i].data);
}
- free(tags->tags);
+ myfree(tags->tags);
}
}
-int i_tags_find(i_img_tags *tags, char *name, int start, int *entry) {
+/*
+=item i_tags_find(tags, name, start, &entry)
+
+=category Tags
+
+Searchs for a tag of the given I<name> starting from index I<start>.
+
+On success returns true and sets *I<entry>.
+
+On failure returns false.
+
+=cut
+*/
+
+int i_tags_find(i_img_tags *tags, char const *name, int start, int *entry) {
if (tags->tags) {
while (start < tags->count) {
if (tags->tags[start].name && strcmp(name, tags->tags[start].name) == 0) {
return 0;
}
+/*
+=item i_tags_findn(tags, code, start, &entry)
+
+=category Tags
+
+Searchs for a tag of the given I<code> starting from index I<start>.
+
+On success returns true and sets *I<entry>.
+
+On failure returns false.
+
+=cut
+*/
+
int i_tags_findn(i_img_tags *tags, int code, int start, int *entry) {
if (tags->tags) {
while (start < tags->count) {
return 0;
}
+/*
+=item i_tags_delete(tags, index)
+
+=category Tags
+
+Delete a tag by index.
+
+Returns true on success.
+
+=cut
+*/
int i_tags_delete(i_img_tags *tags, int entry) {
+ /*printf("i_tags_delete(tags %p [count %d], entry %d)\n",
+ tags, tags->count, entry);*/
if (tags->tags && entry >= 0 && entry < tags->count) {
i_img_tag old = tags->tags[entry];
memmove(tags->tags+entry, tags->tags+entry+1,
- tags->count-entry-1);
+ (tags->count-entry-1) * sizeof(i_img_tag));
if (old.name)
- free(old.name);
+ myfree(old.name);
if (old.data)
- free(old.data);
+ myfree(old.data);
--tags->count;
+
return 1;
}
return 0;
}
-int i_tags_delbyname(i_img_tags *tags, char *name) {
+/*
+=item i_tags_delbyname(tags, name)
+
+=category Tags
+
+Delete any tags with the given name.
+
+Returns the number of tags deleted.
+
+=cut
+*/
+
+int i_tags_delbyname(i_img_tags *tags, char const *name) {
int count = 0;
int i;
+ /*printf("i_tags_delbyname(tags %p [count %d], name %s)\n",
+ tags, tags->count, name);*/
if (tags->tags) {
for (i = tags->count-1; i >= 0; --i) {
if (tags->tags[i].name && strcmp(name, tags->tags[i].name) == 0) {
}
}
}
+ /*i_tags_print(tags);*/
+
return count;
}
+/*
+=item i_tags_delbycode(tags, code)
+
+=category Tags
+
+Delete any tags with the given code.
+
+Returns the number of tags deleted.
+
+=cut
+*/
+
int i_tags_delbycode(i_img_tags *tags, int code) {
int count = 0;
int i;
return count;
}
-int i_tags_get_float(i_img_tags *tags, char *name, int code, double *value) {
+/*
+=item i_tags_get_float(tags, name, code, value)
+
+=category Tags
+
+Retrieves a tag as a floating point value.
+
+If the tag has a string value then that is parsed as a floating point
+number, otherwise the integer value of the tag is used.
+
+On success sets *I<value> and returns true.
+
+On failure returns false.
+
+=cut
+*/
+
+int i_tags_get_float(i_img_tags *tags, char const *name, int code,
+ double *value) {
int index;
i_img_tag *entry;
return 1;
}
-int i_tags_set_float(i_img_tags *tags, char *name, int code, double value) {
+/*
+=item i_tags_set_float(tags, name, code, value)
+
+=category Tags
+
+Equivalent to i_tags_set_float2(tags, name, code, value, 30).
+
+=cut
+*/
+
+int i_tags_set_float(i_img_tags *tags, char const *name, int code,
+ double value) {
+ return i_tags_set_float2(tags, name, code, value, 30);
+}
+
+/*
+=item i_tags_set_float2(tags, name, code, value, places)
+
+=category Tags
+
+Sets the tag with the given name and code to the given floating point
+value.
+
+Since tags are strings or ints, we convert the value to a string before
+storage at the precision specified by C<places>.
+
+=cut
+*/
+
+int i_tags_set_float2(i_img_tags *tags, char const *name, int code,
+ double value, int places) {
char temp[40];
- sprintf(temp, "%.30g", value);
+ if (places < 0)
+ places = 30;
+ else if (places > 30)
+ places = 30;
+
+ sprintf(temp, "%.*g", places, value);
if (name)
i_tags_delbyname(tags, name);
else
return i_tags_add(tags, name, code, temp, strlen(temp), 0);
}
-int i_tags_get_int(i_img_tags *tags, char *name, int code, int *value) {
+/*
+=item i_tags_get_int(tags, name, code, &value)
+
+=category Tags
+
+Retrieve a tag specified by name or code as an integer.
+
+On success sets the int *I<value> to the integer and returns true.
+
+On failure returns false.
+
+=cut
+*/
+
+int i_tags_get_int(i_img_tags *tags, char const *name, int code, int *value) {
int index;
i_img_tag *entry;
return 1;
}
-int i_tags_get_string(i_img_tags *tags, char *name, int code,
+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 NUL terminated.
+
+=cut
+*/
+
+int i_tags_get_string(i_img_tags *tags, char const *name, int code,
char *value, size_t value_size) {
int index;
i_img_tag *entry;
value[cpsize] = '\0';
}
else {
- sprintf(value, "%d", entry->data);
+ sprintf(value, "%d", entry->idata);
}
return 1;
}
+/*
+=item i_tags_set(tags, name, data, size)
+
+=category Tags
+
+Sets the given tag to the string I<data>
+
+=cut
+*/
+
+int
+i_tags_set(i_img_tags *tags, char const *name, char const *data, int size) {
+ i_tags_delbyname(tags, name);
+
+ return i_tags_add(tags, name, 0, data, size, 0);
+}
+
+/*
+=item i_tags_setn(tags, name, idata)
+
+=category Tags
+
+Sets the given tag to the integer I<idata>
+
+=cut
+*/
+
+int
+i_tags_setn(i_img_tags *tags, char const *name, int idata) {
+ i_tags_delbyname(tags, name);
+
+ return i_tags_addn(tags, name, 0, idata);
+}
+
void i_tags_print(i_img_tags *tags) {
int i;
printf("Alloc %d\n", tags->alloc);
i_img_tag *tag = tags->tags + i;
printf("Tag %d\n", i);
if (tag->name)
- printf(" Name : %s\n", tag->name);
+ printf(" Name : %s (%p)\n", tag->name, tag->name);
printf(" Code : %d\n", tag->code);
if (tag->data) {
int pos;
- printf(" Data : %d => '", tag->size);
+ printf(" Data : %d (%p) => '", tag->size, tag->data);
for (pos = 0; pos < tag->size; ++pos) {
if (tag->data[pos] == '\\' || tag->data[pos] == '\'') {
putchar('\\');
}
}
}
+
+/*
+=back
+
+=head1 AUTHOR
+
+Tony Cook <tony@develop-help.com>
+
+=head1 SEE ALSO
+
+Imager(3)
+
+=cut
+*/