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