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("&", fp);
79 break;
80 case '<':
81 fputs("<", fp);
82 break;
83 case '>':
84 fputs(">", 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