|
@@ -14,8 +14,23 @@
|
|
|
#include <grass/gis.h>
|
|
|
#include <grass/glocale.h>
|
|
|
|
|
|
-static char **scan_rules(int *);
|
|
|
-static int cmp(const void *, const void *);
|
|
|
+struct colorinfo
|
|
|
+{
|
|
|
+ char *name;
|
|
|
+ char *desc;
|
|
|
+ char *type;
|
|
|
+};
|
|
|
+
|
|
|
+static struct colorinfo *get_colorinfo(int *);
|
|
|
+static void free_colorinfo(struct colorinfo *, int);
|
|
|
+
|
|
|
+static int cmp_clrname(const void *a, const void *b)
|
|
|
+{
|
|
|
+ struct colorinfo *ca = (struct colorinfo *) a;
|
|
|
+ struct colorinfo *cb = (struct colorinfo *) b;
|
|
|
+
|
|
|
+ return (strcmp(ca->name, cb->name));
|
|
|
+}
|
|
|
|
|
|
/*!
|
|
|
\brief Get list of color rules for Option->options
|
|
@@ -24,18 +39,19 @@ static int cmp(const void *, const void *);
|
|
|
*/
|
|
|
char *G_color_rules_options(void)
|
|
|
{
|
|
|
- char *list, **rules;
|
|
|
+ char *list;
|
|
|
const char *name;
|
|
|
int size, len, nrules;
|
|
|
int i, n;
|
|
|
+ struct colorinfo *colorinfo;
|
|
|
|
|
|
list = NULL;
|
|
|
size = len = 0;
|
|
|
|
|
|
- rules = scan_rules(&nrules);
|
|
|
+ colorinfo = get_colorinfo(&nrules);
|
|
|
|
|
|
for (i = 0; i < nrules; i++) {
|
|
|
- name = rules[i];
|
|
|
+ name = colorinfo[i].name;
|
|
|
n = strlen(name);
|
|
|
|
|
|
if (size < len + n + 2) {
|
|
@@ -50,7 +66,7 @@ char *G_color_rules_options(void)
|
|
|
len += n;
|
|
|
}
|
|
|
|
|
|
- G_free(rules);
|
|
|
+ free_colorinfo(colorinfo, nrules);
|
|
|
|
|
|
return list;
|
|
|
}
|
|
@@ -62,27 +78,21 @@ char *G_color_rules_options(void)
|
|
|
*/
|
|
|
char *G_color_rules_descriptions(void)
|
|
|
{
|
|
|
- char path[GPATH_MAX];
|
|
|
- struct Key_Value *kv;
|
|
|
int result_len, result_max;
|
|
|
- char *result, **rules;
|
|
|
+ char *result;
|
|
|
const char *name, *desc;
|
|
|
int i, len, nrules;
|
|
|
+ struct colorinfo *colorinfo;
|
|
|
|
|
|
result_len = 0;
|
|
|
result_max = 2000;
|
|
|
result = G_malloc(result_max);
|
|
|
-
|
|
|
- G_snprintf(path, GPATH_MAX, "%s/etc/colors.desc", G_gisbase());
|
|
|
- kv = G_read_key_value_file(path);
|
|
|
- if (!kv)
|
|
|
- return NULL;
|
|
|
|
|
|
- rules = scan_rules(&nrules);
|
|
|
+ colorinfo = get_colorinfo(&nrules);
|
|
|
|
|
|
for (i = 0; i < nrules; i++) {
|
|
|
- name = rules[i];
|
|
|
- desc = G_find_key_value(name, kv);
|
|
|
+ name = colorinfo[i].name;
|
|
|
+ desc = colorinfo[i].desc;
|
|
|
|
|
|
if (!desc)
|
|
|
desc = _("no description");
|
|
@@ -99,54 +109,131 @@ char *G_color_rules_descriptions(void)
|
|
|
result_len += len;
|
|
|
}
|
|
|
|
|
|
- G_free_key_value(kv);
|
|
|
- G_free(rules);
|
|
|
+ free_colorinfo(colorinfo, nrules);
|
|
|
|
|
|
return result;
|
|
|
}
|
|
|
|
|
|
-char **scan_rules(int *nrules)
|
|
|
-{
|
|
|
- char **rules;
|
|
|
- char path[GPATH_MAX];
|
|
|
-
|
|
|
- G_snprintf(path, GPATH_MAX, "%s/etc/colors", G_gisbase());
|
|
|
+/*!
|
|
|
+ \brief Get color rules description for Option->descriptions
|
|
|
|
|
|
- rules = G_ls2(path, nrules);
|
|
|
+ The type of color rule including range is appended to the description
|
|
|
|
|
|
- rules = G_realloc(rules, (*nrules + 3) * sizeof (const char *));
|
|
|
+ \return allocated buffer with name, description, and type
|
|
|
+*/
|
|
|
+char *G_color_rules_description_type(void)
|
|
|
+{
|
|
|
+ int i, len, nrules;
|
|
|
+ struct colorinfo *colorinfo;
|
|
|
+ const char *name, *desc, *type;
|
|
|
+ int result_len, result_max;
|
|
|
+ char *result;
|
|
|
+
|
|
|
+ colorinfo = get_colorinfo(&nrules);
|
|
|
|
|
|
- rules[(*nrules)++] = G_store("random");
|
|
|
- rules[(*nrules)++] = G_store("grey.eq");
|
|
|
- rules[(*nrules)++] = G_store("grey.log");
|
|
|
+ result_len = 0;
|
|
|
+ result_max = 2000;
|
|
|
+ result = G_malloc(result_max);
|
|
|
|
|
|
- qsort(rules, *nrules, sizeof (char *), cmp);
|
|
|
+ for (i = 0; i < nrules; i++) {
|
|
|
+ name = colorinfo[i].name;
|
|
|
+ desc = colorinfo[i].desc;
|
|
|
+ type = colorinfo[i].type;
|
|
|
+
|
|
|
+ if (desc) {
|
|
|
+ len = strlen(name) + strlen(desc) + strlen(type) + 5;
|
|
|
+ if (result_len + len >= result_max) {
|
|
|
+ result_max = result_len + len + 1000;
|
|
|
+ result = G_realloc(result, result_max);
|
|
|
+ }
|
|
|
+
|
|
|
+ sprintf(result + result_len, "%s;%s [%s];", name, desc, type);
|
|
|
+ result_len += len;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ len = strlen(name) + strlen(type) + 5;
|
|
|
+ if (result_len + len >= result_max) {
|
|
|
+ result_max = result_len + len + 1000;
|
|
|
+ result = G_realloc(result, result_max);
|
|
|
+ }
|
|
|
+
|
|
|
+ sprintf(result + result_len, "%s; [%s];", name, type);
|
|
|
+ result_len += len;
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- return rules;
|
|
|
+ free_colorinfo(colorinfo, nrules);
|
|
|
+
|
|
|
+ return result;
|
|
|
}
|
|
|
|
|
|
-int cmp(const void *aa, const void *bb)
|
|
|
+/*!
|
|
|
+ \brief Print color rules
|
|
|
+
|
|
|
+ \param out file where to print
|
|
|
+*/
|
|
|
+void G_list_color_rules(FILE *out)
|
|
|
{
|
|
|
- char *const *a = (char *const *) aa;
|
|
|
- char *const *b = (char *const *) bb;
|
|
|
+ int i, nrules;
|
|
|
+ struct colorinfo *colorinfo;
|
|
|
|
|
|
- return strcmp(*a, *b);
|
|
|
+ colorinfo = get_colorinfo(&nrules);
|
|
|
+
|
|
|
+ for (i = 0; i < nrules; i++)
|
|
|
+ fprintf(out, "%s\n", colorinfo[i].name);
|
|
|
+
|
|
|
+ free_colorinfo(colorinfo, nrules);
|
|
|
}
|
|
|
|
|
|
/*!
|
|
|
- \brief Print color rules
|
|
|
+ \brief Print color rules with description and type
|
|
|
|
|
|
+ The type of color rule including range is appended to the description.
|
|
|
+ If a color rule name is given, color info is printed only for this
|
|
|
+ rule.
|
|
|
+
|
|
|
+ \param name optional color rule name, or NULL
|
|
|
\param out file where to print
|
|
|
*/
|
|
|
-void G_list_color_rules(FILE *out)
|
|
|
+void G_list_color_rules_description_type(FILE *out, char *name)
|
|
|
{
|
|
|
int i, nrules;
|
|
|
- char **rules;
|
|
|
+ struct colorinfo *colorinfo, csearch, *cfound;
|
|
|
+
|
|
|
+ colorinfo = get_colorinfo(&nrules);
|
|
|
+
|
|
|
+ cfound = NULL;
|
|
|
+ if (name) {
|
|
|
+ csearch.name = name;
|
|
|
+ cfound = bsearch(&csearch, colorinfo, nrules,
|
|
|
+ sizeof(struct colorinfo), cmp_clrname);
|
|
|
+
|
|
|
+ if (cfound) {
|
|
|
+ if (cfound->desc) {
|
|
|
+ fprintf(out, "%s: %s [%s]\n", cfound->name,
|
|
|
+ cfound->desc, cfound->type);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ fprintf(out, "%s: [%s]\n", cfound->name,
|
|
|
+ cfound->type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- rules = scan_rules(&nrules);
|
|
|
+ if (cfound == NULL) {
|
|
|
+ for (i = 0; i < nrules; i++) {
|
|
|
+ if (colorinfo[i].desc) {
|
|
|
+ fprintf(out, "%s: %s [%s]\n", colorinfo[i].name,
|
|
|
+ colorinfo[i].desc, colorinfo[i].type);
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ fprintf(out, "%s: [%s]\n", colorinfo[i].name,
|
|
|
+ colorinfo[i].type);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- for (i = 0; i < nrules; i++)
|
|
|
- fprintf(out, "%s\n", rules[i]);
|
|
|
+ free_colorinfo(colorinfo, nrules);
|
|
|
}
|
|
|
|
|
|
/*!
|
|
@@ -159,14 +246,172 @@ void G_list_color_rules(FILE *out)
|
|
|
*/
|
|
|
int G_find_color_rule(const char *name)
|
|
|
{
|
|
|
- int i, nrules;
|
|
|
- char **rules;
|
|
|
-
|
|
|
- rules = scan_rules(&nrules);
|
|
|
+ int result, nrules;
|
|
|
+ struct colorinfo *colorinfo, csearch;
|
|
|
|
|
|
- for (i = 0; i < nrules; i++)
|
|
|
- if (strcmp(name, rules[i]) == 0)
|
|
|
- return 1;
|
|
|
+ colorinfo = get_colorinfo(&nrules);
|
|
|
+
|
|
|
+ csearch.name = (char *)name;
|
|
|
+ result = (bsearch(&csearch, colorinfo, nrules,
|
|
|
+ sizeof(struct colorinfo), cmp_clrname) != NULL);
|
|
|
+
|
|
|
+ free_colorinfo(colorinfo, nrules);
|
|
|
+
|
|
|
+ return result;
|
|
|
+}
|
|
|
+
|
|
|
+struct colorinfo *get_colorinfo(int *nrules)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ char path[GPATH_MAX];
|
|
|
+ FILE *fp;
|
|
|
+ struct colorinfo *colorinfo;
|
|
|
+ char **cnames;
|
|
|
+
|
|
|
+ /* load color rules */
|
|
|
+ G_snprintf(path, GPATH_MAX, "%s/etc/colors", G_gisbase());
|
|
|
|
|
|
- return 0;
|
|
|
+ *nrules = 0;
|
|
|
+ cnames = G_ls2(path, nrules);
|
|
|
+ (*nrules) += 3;
|
|
|
+ colorinfo = G_malloc(*nrules * sizeof(struct colorinfo));
|
|
|
+ for (i = 0; i < *nrules - 3; i++) {
|
|
|
+ char buf[1024];
|
|
|
+ double rmin, rmax;
|
|
|
+ int first;
|
|
|
+ int cisperc;
|
|
|
+
|
|
|
+ colorinfo[i].name = G_store(cnames[i]);
|
|
|
+ colorinfo[i].desc = NULL;
|
|
|
+
|
|
|
+ /* open color rule file */
|
|
|
+ G_snprintf(path, GPATH_MAX, "%s/etc/colors/%s", G_gisbase(),
|
|
|
+ colorinfo[i].name);
|
|
|
+ fp = fopen(path, "r");
|
|
|
+ if (!fp)
|
|
|
+ G_fatal_error(_("Unable to open color rule"));
|
|
|
+
|
|
|
+ /* scan all lines */
|
|
|
+ first = 1;
|
|
|
+ rmin = rmax = 0;
|
|
|
+ cisperc = 0;
|
|
|
+ while (G_getl2(buf, sizeof(buf), fp)) {
|
|
|
+ char value[80], color[80];
|
|
|
+ double x;
|
|
|
+ char c;
|
|
|
+
|
|
|
+ G_strip(buf);
|
|
|
+
|
|
|
+ if (*buf == '\0')
|
|
|
+ continue;
|
|
|
+ if (*buf == '#')
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (sscanf(buf, "%s %[^\n]", value, color) != 2)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ if (G_strcasecmp(value, "default") == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (G_strcasecmp(value, "nv") == 0) {
|
|
|
+ continue;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
|
|
|
+ cisperc = 1;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (sscanf(value, "%lf", &x) == 1) {
|
|
|
+ if (first) {
|
|
|
+ first = 0;
|
|
|
+ rmin = rmax = x;
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ if (rmin > x)
|
|
|
+ rmin = x;
|
|
|
+ if (rmax < x)
|
|
|
+ rmax = x;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ fclose(fp);
|
|
|
+
|
|
|
+ if (cisperc)
|
|
|
+ colorinfo[i].type = G_store(_("range: map values"));
|
|
|
+ else {
|
|
|
+ G_snprintf(buf, sizeof(buf) - 1, _("range: %g to %g"), rmin, rmax);
|
|
|
+ colorinfo[i].type = G_store(buf);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ G_free(cnames);
|
|
|
+
|
|
|
+ /* colors without rules but description */
|
|
|
+ colorinfo[*nrules - 3].name = G_store("random");
|
|
|
+ colorinfo[*nrules - 3].desc = NULL;
|
|
|
+ colorinfo[*nrules - 3].type = G_store(_("range: map values"));
|
|
|
+
|
|
|
+ colorinfo[*nrules - 2].name = G_store("grey.eq");
|
|
|
+ colorinfo[*nrules - 2].desc = NULL;
|
|
|
+ colorinfo[*nrules - 2].type = G_store(_("range: map values"));
|
|
|
+
|
|
|
+ colorinfo[*nrules - 1].name = G_store("grey.log");
|
|
|
+ colorinfo[*nrules - 1].desc = NULL;
|
|
|
+ colorinfo[*nrules - 1].type = G_store(_("range: map values"));
|
|
|
+
|
|
|
+ qsort(colorinfo, *nrules, sizeof(struct colorinfo), cmp_clrname);
|
|
|
+
|
|
|
+ /* load color descriptions */
|
|
|
+ G_snprintf(path, GPATH_MAX, "%s/etc/colors.desc", G_gisbase());
|
|
|
+ fp = fopen(path, "r");
|
|
|
+ if (!fp)
|
|
|
+ G_fatal_error(_("Unable to open color descriptions"));
|
|
|
+
|
|
|
+ for (;;) {
|
|
|
+ char buf[1024];
|
|
|
+ char tok_buf[1024];
|
|
|
+ char *cname, *cdesc;
|
|
|
+ int ntokens;
|
|
|
+ char **tokens;
|
|
|
+ struct colorinfo csearch, *cfound;
|
|
|
+
|
|
|
+ if (!G_getl2(buf, sizeof(buf), fp))
|
|
|
+ break;
|
|
|
+ strcpy(tok_buf, buf);
|
|
|
+ tokens = G_tokenize(tok_buf, ":");
|
|
|
+ ntokens = G_number_of_tokens(tokens);
|
|
|
+ if (ntokens != 2)
|
|
|
+ continue;
|
|
|
+
|
|
|
+ cname = G_chop(tokens[0]);
|
|
|
+ cdesc = G_chop(tokens[1]);
|
|
|
+
|
|
|
+ csearch.name = cname;
|
|
|
+ cfound = bsearch(&csearch, colorinfo, *nrules,
|
|
|
+ sizeof(struct colorinfo), cmp_clrname);
|
|
|
+
|
|
|
+ if (cfound) {
|
|
|
+ cfound->desc = G_store(cdesc);
|
|
|
+ }
|
|
|
+ G_free_tokens(tokens);
|
|
|
+ }
|
|
|
+ fclose(fp);
|
|
|
+
|
|
|
+ return colorinfo;
|
|
|
+}
|
|
|
+
|
|
|
+void free_colorinfo(struct colorinfo *colorinfo, int nrules)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+
|
|
|
+ for (i = 0; i < nrules; i++) {
|
|
|
+ if (colorinfo[i].name)
|
|
|
+ G_free(colorinfo[i].name);
|
|
|
+ if (colorinfo[i].desc)
|
|
|
+ G_free(colorinfo[i].desc);
|
|
|
+ if (colorinfo[i].type)
|
|
|
+ G_free(colorinfo[i].type);
|
|
|
+ }
|
|
|
+ if (nrules > 0)
|
|
|
+ G_free(colorinfo);
|
|
|
}
|