1 /*!
2 \file lib/gis/color_rules.c
3
4 \brief GIS Library - Color tables management subroutines
5
6 Taken from r.colors module.
7
8 (C) 2001-2011 by the GRASS Development Team
9 */
10
11 #include <stdlib.h>
12 #include <string.h>
13
14 #include <grass/gis.h>
15 #include <grass/glocale.h>
16
17 struct colorinfo
18 {
19 char *name;
20 char *desc;
21 char *type;
22 };
23
24 static struct colorinfo *get_colorinfo(int *);
25 static void free_colorinfo(struct colorinfo *, int);
26
cmp_clrname(const void * a,const void * b)27 static int cmp_clrname(const void *a, const void *b)
28 {
29 struct colorinfo *ca = (struct colorinfo *) a;
30 struct colorinfo *cb = (struct colorinfo *) b;
31
32 return (strcmp(ca->name, cb->name));
33 }
34
35 /*!
36 \brief Get list of color rules for Option->options
37
38 \return allocated string buffer with options
39 */
G_color_rules_options(void)40 char *G_color_rules_options(void)
41 {
42 char *list;
43 const char *name;
44 int size, len, nrules;
45 int i, n;
46 struct colorinfo *colorinfo;
47
48 list = NULL;
49 size = len = 0;
50
51 colorinfo = get_colorinfo(&nrules);
52
53 for (i = 0; i < nrules; i++) {
54 name = colorinfo[i].name;
55 n = strlen(name);
56
57 if (size < len + n + 2) {
58 size = len + n + 200;
59 list = G_realloc(list, size);
60 }
61
62 if (len > 0)
63 list[len++] = ',';
64
65 memcpy(&list[len], name, n + 1);
66 len += n;
67 }
68
69 free_colorinfo(colorinfo, nrules);
70
71 return list;
72 }
73
74 /*!
75 \brief Get color rules description for Option->descriptions
76
77 \return allocated buffer with descriptions
78 */
G_color_rules_descriptions(void)79 char *G_color_rules_descriptions(void)
80 {
81 int result_len, result_max;
82 char *result;
83 const char *name, *desc;
84 int i, len, nrules;
85 struct colorinfo *colorinfo;
86
87 result_len = 0;
88 result_max = 2000;
89 result = G_malloc(result_max);
90
91 colorinfo = get_colorinfo(&nrules);
92
93 for (i = 0; i < nrules; i++) {
94 name = colorinfo[i].name;
95 desc = colorinfo[i].desc;
96
97 if (!desc)
98 desc = _("no description");
99
100 /* desc = _(desc); */
101
102 len = strlen(name) + strlen(desc) + 2;
103 if (result_len + len >= result_max) {
104 result_max = result_len + len + 1000;
105 result = G_realloc(result, result_max);
106 }
107
108 sprintf(result + result_len, "%s;%s;", name, desc);
109 result_len += len;
110 }
111
112 free_colorinfo(colorinfo, nrules);
113
114 return result;
115 }
116
117 /*!
118 \brief Get color rules description for Option->descriptions
119
120 The type of color rule including range is appended to the description
121
122 \return allocated buffer with name, description, and type
123 */
G_color_rules_description_type(void)124 char *G_color_rules_description_type(void)
125 {
126 int i, len, nrules;
127 struct colorinfo *colorinfo;
128 const char *name, *desc, *type;
129 int result_len, result_max;
130 char *result;
131
132 colorinfo = get_colorinfo(&nrules);
133
134 result_len = 0;
135 result_max = 2000;
136 result = G_malloc(result_max);
137
138 for (i = 0; i < nrules; i++) {
139 name = colorinfo[i].name;
140 desc = colorinfo[i].desc;
141 type = colorinfo[i].type;
142
143 if (desc) {
144 len = strlen(name) + strlen(desc) + strlen(type) + 5;
145 if (result_len + len >= result_max) {
146 result_max = result_len + len + 1000;
147 result = G_realloc(result, result_max);
148 }
149
150 sprintf(result + result_len, "%s;%s [%s];", name, desc, type);
151 result_len += len;
152 }
153 else {
154 len = strlen(name) + strlen(type) + 5;
155 if (result_len + len >= result_max) {
156 result_max = result_len + len + 1000;
157 result = G_realloc(result, result_max);
158 }
159
160 sprintf(result + result_len, "%s; [%s];", name, type);
161 result_len += len;
162 }
163 }
164
165 free_colorinfo(colorinfo, nrules);
166
167 return result;
168 }
169
170 /*!
171 \brief Print color rules
172
173 \param out file where to print
174 */
G_list_color_rules(FILE * out)175 void G_list_color_rules(FILE *out)
176 {
177 int i, nrules;
178 struct colorinfo *colorinfo;
179
180 colorinfo = get_colorinfo(&nrules);
181
182 for (i = 0; i < nrules; i++)
183 fprintf(out, "%s\n", colorinfo[i].name);
184
185 free_colorinfo(colorinfo, nrules);
186 }
187
188 /*!
189 \brief Print color rules with description and type
190
191 The type of color rule including range is appended to the description.
192 If a color rule name is given, color info is printed only for this
193 rule.
194
195 \param name optional color rule name, or NULL
196 \param out file where to print
197 */
G_list_color_rules_description_type(FILE * out,char * name)198 void G_list_color_rules_description_type(FILE *out, char *name)
199 {
200 int i, nrules;
201 struct colorinfo *colorinfo, csearch, *cfound;
202
203 colorinfo = get_colorinfo(&nrules);
204
205 cfound = NULL;
206 if (name) {
207 csearch.name = name;
208 cfound = bsearch(&csearch, colorinfo, nrules,
209 sizeof(struct colorinfo), cmp_clrname);
210
211 if (cfound) {
212 if (cfound->desc) {
213 fprintf(out, "%s: %s [%s]\n", cfound->name,
214 cfound->desc, cfound->type);
215 }
216 else {
217 fprintf(out, "%s: [%s]\n", cfound->name,
218 cfound->type);
219 }
220 }
221 }
222
223 if (cfound == NULL) {
224 for (i = 0; i < nrules; i++) {
225 if (colorinfo[i].desc) {
226 fprintf(out, "%s: %s [%s]\n", colorinfo[i].name,
227 colorinfo[i].desc, colorinfo[i].type);
228 }
229 else {
230 fprintf(out, "%s: [%s]\n", colorinfo[i].name,
231 colorinfo[i].type);
232 }
233 }
234 }
235
236 free_colorinfo(colorinfo, nrules);
237 }
238
239 /*!
240 \brief Check if color rule is defined
241
242 \param name color rule name
243
244 \return 1 found
245 \return 0 not found
246 */
G_find_color_rule(const char * name)247 int G_find_color_rule(const char *name)
248 {
249 int result, nrules;
250 struct colorinfo *colorinfo, csearch;
251
252 colorinfo = get_colorinfo(&nrules);
253
254 csearch.name = (char *)name;
255 result = (bsearch(&csearch, colorinfo, nrules,
256 sizeof(struct colorinfo), cmp_clrname) != NULL);
257
258 free_colorinfo(colorinfo, nrules);
259
260 return result;
261 }
262
get_colorinfo(int * nrules)263 struct colorinfo *get_colorinfo(int *nrules)
264 {
265 int i;
266 char path[GPATH_MAX];
267 FILE *fp;
268 struct colorinfo *colorinfo;
269 char **cnames;
270
271 /* load color rules */
272 G_snprintf(path, GPATH_MAX, "%s/etc/colors", G_gisbase());
273
274 *nrules = 0;
275 cnames = G_ls2(path, nrules);
276 (*nrules) += 3;
277 colorinfo = G_malloc(*nrules * sizeof(struct colorinfo));
278 for (i = 0; i < *nrules - 3; i++) {
279 char buf[1024];
280 double rmin, rmax;
281 int first;
282 int cisperc;
283
284 colorinfo[i].name = G_store(cnames[i]);
285 colorinfo[i].desc = NULL;
286
287 /* open color rule file */
288 G_snprintf(path, GPATH_MAX, "%s/etc/colors/%s", G_gisbase(),
289 colorinfo[i].name);
290 fp = fopen(path, "r");
291 if (!fp)
292 G_fatal_error(_("Unable to open color rule"));
293
294 /* scan all lines */
295 first = 1;
296 rmin = rmax = 0;
297 cisperc = 0;
298 while (G_getl2(buf, sizeof(buf), fp)) {
299 char value[80], color[80];
300 double x;
301 char c;
302
303 G_strip(buf);
304
305 if (*buf == '\0')
306 continue;
307 if (*buf == '#')
308 continue;
309
310 if (sscanf(buf, "%s %[^\n]", value, color) != 2)
311 continue;
312
313 if (G_strcasecmp(value, "default") == 0) {
314 continue;
315 }
316
317 if (G_strcasecmp(value, "nv") == 0) {
318 continue;
319 }
320
321 if (sscanf(value, "%lf%c", &x, &c) == 2 && c == '%') {
322 cisperc = 1;
323 break;
324 }
325 if (sscanf(value, "%lf", &x) == 1) {
326 if (first) {
327 first = 0;
328 rmin = rmax = x;
329 }
330 else {
331 if (rmin > x)
332 rmin = x;
333 if (rmax < x)
334 rmax = x;
335 }
336 }
337 }
338 fclose(fp);
339
340 if (cisperc)
341 colorinfo[i].type = G_store(_("range: map values"));
342 else {
343 G_snprintf(buf, sizeof(buf) - 1, _("range: %g to %g"), rmin, rmax);
344 colorinfo[i].type = G_store(buf);
345 }
346 }
347 G_free(cnames);
348
349 /* colors without rules but description */
350 colorinfo[*nrules - 3].name = G_store("random");
351 colorinfo[*nrules - 3].desc = NULL;
352 colorinfo[*nrules - 3].type = G_store(_("range: map values"));
353
354 colorinfo[*nrules - 2].name = G_store("grey.eq");
355 colorinfo[*nrules - 2].desc = NULL;
356 colorinfo[*nrules - 2].type = G_store(_("range: map values"));
357
358 colorinfo[*nrules - 1].name = G_store("grey.log");
359 colorinfo[*nrules - 1].desc = NULL;
360 colorinfo[*nrules - 1].type = G_store(_("range: map values"));
361
362 qsort(colorinfo, *nrules, sizeof(struct colorinfo), cmp_clrname);
363
364 /* load color descriptions */
365 G_snprintf(path, GPATH_MAX, "%s/etc/colors.desc", G_gisbase());
366 fp = fopen(path, "r");
367 if (!fp)
368 G_fatal_error(_("Unable to open color descriptions"));
369
370 for (;;) {
371 char buf[1024];
372 char tok_buf[1024];
373 char *cname, *cdesc;
374 int ntokens;
375 char **tokens;
376 struct colorinfo csearch, *cfound;
377
378 if (!G_getl2(buf, sizeof(buf), fp))
379 break;
380 strcpy(tok_buf, buf);
381 tokens = G_tokenize(tok_buf, ":");
382 ntokens = G_number_of_tokens(tokens);
383 if (ntokens != 2)
384 continue;
385
386 cname = G_chop(tokens[0]);
387 cdesc = G_chop(tokens[1]);
388
389 csearch.name = cname;
390 cfound = bsearch(&csearch, colorinfo, *nrules,
391 sizeof(struct colorinfo), cmp_clrname);
392
393 if (cfound) {
394 cfound->desc = G_store(cdesc);
395 }
396 G_free_tokens(tokens);
397 }
398 fclose(fp);
399
400 return colorinfo;
401 }
402
free_colorinfo(struct colorinfo * colorinfo,int nrules)403 void free_colorinfo(struct colorinfo *colorinfo, int nrules)
404 {
405 int i;
406
407 for (i = 0; i < nrules; i++) {
408 if (colorinfo[i].name)
409 G_free(colorinfo[i].name);
410 if (colorinfo[i].desc)
411 G_free(colorinfo[i].desc);
412 if (colorinfo[i].type)
413 G_free(colorinfo[i].type);
414 }
415 if (nrules > 0)
416 G_free(colorinfo);
417 }
418