1 /*!
2  * \file lib/gis/parser_interface.c
3  *
4  * \brief GIS Library - Argument parsing functions (interface)
5  *
6  * (C) 2001-2009 by the GRASS Development Team
7  *
8  * This program is free software under the GNU General Public License
9  * (>=v2). Read the file COPYING that comes with GRASS for details.
10  *
11  * \author Original author CERL
12  * \author Soeren Gebbert added Dec. 2009 WPS process_description document
13  */
14 
15 #include <grass/config.h>
16 
17 #include <stdio.h>
18 #include <stdlib.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <unistd.h>
22 #include <stdarg.h>
23 #include <sys/types.h>
24 
25 #if defined(HAVE_LANGINFO_H)
26 #include <langinfo.h>
27 #endif
28 #if defined(__MINGW32__) && defined(USE_NLS)
29 #include <localcharset.h>
30 #endif
31 #ifdef HAVE_ICONV_H
32 #include <iconv.h>
33 #endif
34 
35 #include <grass/gis.h>
36 #include <grass/glocale.h>
37 #include <grass/spawn.h>
38 
39 #include "parser_local_proto.h"
40 
41 #ifdef HAVE_ICONV_H
42 static const char *src_enc;
43 #endif
44 
45 /*!
46  * \brief Formats text for XML.
47  *
48  * \param[in,out] fp file to write to
49  * \param str string to write
50  */
print_escaped_for_xml(FILE * fp,const char * str)51 static void print_escaped_for_xml(FILE *fp, const char *str)
52 {
53 #ifdef HAVE_ICONV_H
54     iconv_t conv = iconv_open("UTF-8", src_enc);
55     char *enc = NULL;
56 
57     if (conv != (iconv_t) -1)
58     {
59 	char *src = (char *) str;
60 	size_t srclen = strlen(src);
61 	size_t dstlen = srclen * 4 + 1;
62 	char *dst = G_alloca(dstlen);
63 	size_t ret;
64 
65 	enc = dst;
66 
67 	ret = iconv(conv, (char **)&src, &srclen, &dst, &dstlen);
68 	if (ret != (size_t) -1 && srclen == 0) {
69 	    str = enc;
70 	    *dst = '\0';
71 	}
72     }
73 #endif
74 
75     for (; *str; str++) {
76 	switch (*str) {
77 	case '&':
78 	    fputs("&amp;", fp);
79 	    break;
80 	case '<':
81 	    fputs("&lt;", fp);
82 	    break;
83 	case '>':
84 	    fputs("&gt;", fp);
85 	    break;
86 	default:
87 	    fputc(*str, fp);
88 	}
89     }
90 
91 #ifdef HAVE_ICONV_H
92     if (enc)
93 	G_freea(enc);
94 
95     if (conv != (iconv_t) -1)
96 	iconv_close(conv);
97 #endif
98 }
99 
100 /*!
101   \brief Print module usage description in XML format.
102 */
G__usage_xml(void)103 void G__usage_xml(void)
104 {
105     struct Option *opt;
106     struct Flag *flag;
107     char *type;
108     char *s, *top;
109     int i;
110     const char *encoding;
111     int new_prompt = 0;
112 
113     new_prompt = G__uses_new_gisprompt();
114 
115     /* gettext converts strings to encoding returned by nl_langinfo(CODESET) */
116 
117 #if defined(HAVE_LANGINFO_H)
118     encoding = nl_langinfo(CODESET);
119 #elif defined(__MINGW32__) && defined(USE_NLS)
120     encoding = locale_charset();
121 #endif
122 
123     if (!encoding || strlen(encoding) == 0)
124 	encoding = "UTF-8";
125 
126 #ifdef HAVE_ICONV_H
127     src_enc = encoding;
128     encoding = "UTF-8";
129 #endif
130 
131     if (!st->pgm_name)		/* v.dave && r.michael */
132 	st->pgm_name = G_program_name();
133     if (!st->pgm_name)
134 	st->pgm_name = "??";
135 
136     fprintf(stdout, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding);
137     fprintf(stdout, "<!DOCTYPE task SYSTEM \"grass-interface.dtd\">\n");
138 
139     fprintf(stdout, "<task name=\"%s\">\n", st->pgm_name);
140 
141     if (st->module_info.label) {
142 	fprintf(stdout, "\t<label>\n\t\t");
143 	print_escaped_for_xml(stdout, st->module_info.label);
144 	fprintf(stdout, "\n\t</label>\n");
145     }
146 
147     if (st->module_info.description) {
148 	fprintf(stdout, "\t<description>\n\t\t");
149 	print_escaped_for_xml(stdout, st->module_info.description);
150 	fprintf(stdout, "\n\t</description>\n");
151     }
152 
153     if (st->module_info.keywords) {
154 	fprintf(stdout, "\t<keywords>\n\t\t");
155 	G__print_keywords(stdout, print_escaped_for_xml);
156 	fprintf(stdout, "\n\t</keywords>\n");
157     }
158 
159 	/***** Don't use parameter-groups for now.  We'll reimplement this later
160 	 ***** when we have a concept of several mutually exclusive option
161 	 ***** groups
162 	if (st->n_opts || st->n_flags)
163 		fprintf(stdout, "\t<parameter-group>\n");
164 	 *****
165 	 *****
166 	 *****/
167 
168     if (st->n_opts) {
169 	opt = &st->first_option;
170 	while (opt != NULL) {
171 	    /* TODO: make this a enumeration type? */
172 	    switch (opt->type) {
173 	    case TYPE_INTEGER:
174 		type = "integer";
175 		break;
176 	    case TYPE_DOUBLE:
177 		type = "float";
178 		break;
179 	    case TYPE_STRING:
180 		type = "string";
181 		break;
182 	    default:
183 		type = "string";
184 		break;
185 	    }
186 	    fprintf(stdout, "\t<parameter "
187 		    "name=\"%s\" "
188 		    "type=\"%s\" "
189 		    "required=\"%s\" "
190 		    "multiple=\"%s\">\n",
191 		    opt->key,
192 		    type,
193 		    opt->required == YES ? "yes" : "no",
194 		    opt->multiple == YES ? "yes" : "no");
195 
196 	    if (opt->label) {
197 		fprintf(stdout, "\t\t<label>\n\t\t\t");
198 		print_escaped_for_xml(stdout, opt->label);
199 		fprintf(stdout, "\n\t\t</label>\n");
200 	    }
201 
202 	    if (opt->description) {
203 		fprintf(stdout, "\t\t<description>\n\t\t\t");
204 		print_escaped_for_xml(stdout, opt->description);
205 		fprintf(stdout, "\n\t\t</description>\n");
206 	    }
207 
208 	    if (opt->key_desc) {
209 		fprintf(stdout, "\t\t<keydesc>\n");
210 		top = G_calloc(strlen(opt->key_desc) + 1, 1);
211 		strcpy(top, opt->key_desc);
212 		s = strtok(top, ",");
213 		for (i = 1; s != NULL; i++) {
214 		    fprintf(stdout, "\t\t\t<item order=\"%d\">", i);
215 		    print_escaped_for_xml(stdout, s);
216 		    fprintf(stdout, "</item>\n");
217 		    s = strtok(NULL, ",");
218 		}
219 		fprintf(stdout, "\t\t</keydesc>\n");
220 		G_free(top);
221 	    }
222 
223 	    if (opt->gisprompt) {
224 		const char *atts[] = { "age", "element", "prompt", NULL };
225 		top = G_calloc(strlen(opt->gisprompt) + 1, 1);
226 		strcpy(top, opt->gisprompt);
227 		s = strtok(top, ",");
228 		fprintf(stdout, "\t\t<gisprompt ");
229 		for (i = 0; s != NULL && atts[i] != NULL; i++) {
230 		    fprintf(stdout, "%s=\"%s\" ", atts[i], s);
231 		    s = strtok(NULL, ",");
232 		}
233 		fprintf(stdout, "/>\n");
234 		G_free(top);
235 	    }
236 
237 	    if (opt->def) {
238 		fprintf(stdout, "\t\t<default>\n\t\t\t");
239 		print_escaped_for_xml(stdout, opt->def);
240 		fprintf(stdout, "\n\t\t</default>\n");
241 	    }
242 
243 	    if (opt->options) {
244 		/* TODO:
245 		 * add something like
246 		 *       <range min="xxx" max="xxx"/>
247 		 * to <values> */
248 		i = 0;
249 		fprintf(stdout, "\t\t<values>\n");
250 		while (opt->opts[i]) {
251 		    fprintf(stdout, "\t\t\t<value>\n");
252 		    fprintf(stdout, "\t\t\t\t<name>");
253 		    print_escaped_for_xml(stdout, opt->opts[i]);
254 		    fprintf(stdout, "</name>\n");
255 		    if (opt->descs && opt->opts[i] && opt->descs[i]) {
256 			fprintf(stdout, "\t\t\t\t<description>");
257 			print_escaped_for_xml(stdout, opt->descs[i]);
258 			fprintf(stdout, "</description>\n");
259 		    }
260 		    fprintf(stdout, "\t\t\t</value>\n");
261 		    i++;
262 		}
263 		fprintf(stdout, "\t\t</values>\n");
264 	    }
265 	    if (opt->guisection) {
266 		fprintf(stdout, "\t\t<guisection>\n\t\t\t");
267 		print_escaped_for_xml(stdout, opt->guisection);
268 		fprintf(stdout, "\n\t\t</guisection>\n");
269 	    }
270 	    if (opt->guidependency) {
271 		fprintf(stdout, "\t\t<guidependency>\n\t\t\t");
272 		print_escaped_for_xml(stdout, opt->guidependency);
273 		fprintf(stdout, "\n\t\t</guidependency>\n");
274 	    }
275 	    /* TODO:
276 	     * - key_desc?
277 	     * - there surely are some more. which ones?
278 	     */
279 
280 	    opt = opt->next_opt;
281 	    fprintf(stdout, "\t</parameter>\n");
282 	}
283     }
284 
285 
286     if (st->n_flags) {
287 	flag = &st->first_flag;
288 	while (flag != NULL) {
289 	    fprintf(stdout, "\t<flag name=\"%c\">\n", flag->key);
290 
291 	    if (flag->label) {
292 		fprintf(stdout, "\t\t<label>\n\t\t\t");
293 		print_escaped_for_xml(stdout, flag->label);
294 		fprintf(stdout, "\n\t\t</label>\n");
295 	    }
296 
297 	    if (flag->suppress_required)
298 		fprintf(stdout, "\t\t<suppress_required/>\n");
299 
300 	    if (flag->description) {
301 		fprintf(stdout, "\t\t<description>\n\t\t\t");
302 		print_escaped_for_xml(stdout, flag->description);
303 		fprintf(stdout, "\n\t\t</description>\n");
304 	    }
305 	    if (flag->guisection) {
306 		fprintf(stdout, " \t\t<guisection>\n\t\t\t");
307 		print_escaped_for_xml(stdout, flag->guisection);
308 		fprintf(stdout, "\n\t\t</guisection>\n");
309 	    }
310 	    flag = flag->next_flag;
311 	    fprintf(stdout, "\t</flag>\n");
312 	}
313     }
314 
315 	/***** Don't use parameter-groups for now.  We'll reimplement this later
316 	 ***** when we have a concept of several mutually exclusive option
317 	 ***** groups
318 	if (st->n_opts || st->n_flags)
319 		fprintf(stdout, "\t</parameter-group>\n");
320 	 *****
321 	 *****
322 	 *****/
323 
324     if (new_prompt) {
325 	/* overwrite */
326 	fprintf(stdout, "\t<flag name=\"%s\">\n", "overwrite");
327 	fprintf(stdout, "\t\t<description>\n\t\t\t");
328 	print_escaped_for_xml(stdout,
329 			      _("Allow output files to overwrite existing files"));
330 	fprintf(stdout, "\n\t\t</description>\n");
331 	fprintf(stdout, "\t</flag>\n");
332     }
333 
334     /* help */
335     fprintf(stdout, "\t<flag name=\"%s\">\n", "help");
336     fprintf(stdout, "\t\t<description>\n\t\t\t");
337     print_escaped_for_xml(stdout, _("Print usage summary"));
338     fprintf(stdout, "\n\t\t</description>\n");
339     fprintf(stdout, "\t</flag>\n");
340 
341     /* verbose */
342     fprintf(stdout, "\t<flag name=\"%s\">\n", "verbose");
343     fprintf(stdout, "\t\t<description>\n\t\t\t");
344     print_escaped_for_xml(stdout, _("Verbose module output"));
345     fprintf(stdout, "\n\t\t</description>\n");
346     fprintf(stdout, "\t</flag>\n");
347 
348     /* quiet */
349     fprintf(stdout, "\t<flag name=\"%s\">\n", "quiet");
350     fprintf(stdout, "\t\t<description>\n\t\t\t");
351     print_escaped_for_xml(stdout, _("Quiet module output"));
352     fprintf(stdout, "\n\t\t</description>\n");
353     fprintf(stdout, "\t</flag>\n");
354 
355     G__describe_option_rules_xml(stdout);
356 
357     fprintf(stdout, "</task>\n");
358 }
359