GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-3df7050671
parser_interface.c
Go to the documentation of this file.
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  */
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  char *src = (char *)str;
59  size_t srclen = strlen(src);
60  size_t dstlen = srclen * 4 + 1;
61  char *dst = G_alloca(dstlen);
62  size_t ret;
63 
64  enc = dst;
65 
66  ret = iconv(conv, (char **)&src, &srclen, &dst, &dstlen);
67  if (ret != (size_t)-1 && srclen == 0) {
68  str = enc;
69  *dst = '\0';
70  }
71  }
72 #endif
73 
74  for (; *str; str++) {
75  switch (*str) {
76  case '&':
77  fputs("&amp;", fp);
78  break;
79  case '<':
80  fputs("&lt;", fp);
81  break;
82  case '>':
83  fputs("&gt;", fp);
84  break;
85  default:
86  fputc(*str, fp);
87  }
88  }
89 
90 #ifdef HAVE_ICONV_H
91  if (enc) {
92  G_freea(enc);
93  }
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  */
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 = NULL;
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 /* check if local_charset() comes from iconv. If so check for iconv library
118  * before using it */
119 #if defined(HAVE_LANGINFO_H)
120  encoding = nl_langinfo(CODESET);
121 #elif defined(_WIN32) && defined(USE_NLS)
122  encoding = locale_charset();
123 #endif
124 
125  if (!encoding || strlen(encoding) == 0)
126  encoding = "UTF-8";
127 
128 #ifdef HAVE_ICONV_H
129  src_enc = encoding;
130  encoding = "UTF-8";
131 #endif
132 
133  if (!st->pgm_name) /* v.dave && r.michael */
134  st->pgm_name = G_program_name();
135  if (!st->pgm_name)
136  st->pgm_name = "??";
137 
138  fprintf(stdout, "<?xml version=\"1.0\" encoding=\"%s\"?>\n", encoding);
139  fprintf(stdout, "<!DOCTYPE task SYSTEM \"grass-interface.dtd\">\n");
140 
141  fprintf(stdout, "<task name=\"%s\">\n", st->pgm_name);
142 
143  if (st->module_info.label) {
144  fprintf(stdout, "\t<label>\n\t\t");
145  print_escaped_for_xml(stdout, st->module_info.label);
146  fprintf(stdout, "\n\t</label>\n");
147  }
148 
149  if (st->module_info.description) {
150  fprintf(stdout, "\t<description>\n\t\t");
151  print_escaped_for_xml(stdout, st->module_info.description);
152  fprintf(stdout, "\n\t</description>\n");
153  }
154 
155  if (st->module_info.keywords) {
156  fprintf(stdout, "\t<keywords>\n\t\t");
157  G__print_keywords(stdout, print_escaped_for_xml, FALSE);
158  fprintf(stdout, "\n\t</keywords>\n");
159  }
160 
161  /***** Don't use parameter-groups for now. We'll reimplement this later
162  ***** when we have a concept of several mutually exclusive option
163  ***** groups
164  if (st->n_opts || st->n_flags)
165  fprintf(stdout, "\t<parameter-group>\n");
166  *****
167  *****
168  *****/
169 
170  if (st->n_opts) {
171  opt = &st->first_option;
172  while (opt != NULL) {
173  /* TODO: make this a enumeration type? */
174  switch (opt->type) {
175  case TYPE_INTEGER:
176  type = "integer";
177  break;
178  case TYPE_DOUBLE:
179  type = "float";
180  break;
181  case TYPE_STRING:
182  type = "string";
183  break;
184  default:
185  type = "string";
186  break;
187  }
188  fprintf(stdout,
189  "\t<parameter "
190  "name=\"%s\" "
191  "type=\"%s\" "
192  "required=\"%s\" "
193  "multiple=\"%s\">\n",
194  opt->key, type, opt->required == YES ? "yes" : "no",
195  opt->multiple == YES ? "yes" : "no");
196 
197  if (opt->label) {
198  fprintf(stdout, "\t\t<label>\n\t\t\t");
199  print_escaped_for_xml(stdout, opt->label);
200  fprintf(stdout, "\n\t\t</label>\n");
201  }
202 
203  if (opt->description) {
204  fprintf(stdout, "\t\t<description>\n\t\t\t");
205  print_escaped_for_xml(stdout, opt->description);
206  fprintf(stdout, "\n\t\t</description>\n");
207  }
208 
209  if (opt->key_desc) {
210  fprintf(stdout, "\t\t<keydesc>\n");
211  top = G_calloc(strlen(opt->key_desc) + 1, 1);
212  strcpy(top, opt->key_desc);
213  s = strtok(top, ",");
214  for (i = 1; s != NULL; i++) {
215  fprintf(stdout, "\t\t\t<item order=\"%d\">", i);
216  print_escaped_for_xml(stdout, s);
217  fprintf(stdout, "</item>\n");
218  s = strtok(NULL, ",");
219  }
220  fprintf(stdout, "\t\t</keydesc>\n");
221  G_free(top);
222  }
223 
224  if (opt->gisprompt) {
225  const char *atts[] = {"age", "element", "prompt", NULL};
226  top = G_calloc(strlen(opt->gisprompt) + 1, 1);
227  strcpy(top, opt->gisprompt);
228  s = strtok(top, ",");
229  fprintf(stdout, "\t\t<gisprompt ");
230  for (i = 0; s != NULL && atts[i] != NULL; i++) {
231  fprintf(stdout, "%s=\"%s\" ", atts[i], s);
232  s = strtok(NULL, ",");
233  }
234  fprintf(stdout, "/>\n");
235  G_free(top);
236  }
237 
238  if (opt->def) {
239  fprintf(stdout, "\t\t<default>\n\t\t\t");
240  print_escaped_for_xml(stdout, opt->def);
241  fprintf(stdout, "\n\t\t</default>\n");
242  }
243 
244  if (opt->options) {
245  /* TODO:
246  * add something like
247  * <range min="xxx" max="xxx"/>
248  * to <values> */
249  i = 0;
250  fprintf(stdout, "\t\t<values>\n");
251  while (opt->opts[i]) {
252  fprintf(stdout, "\t\t\t<value>\n");
253  fprintf(stdout, "\t\t\t\t<name>");
254  print_escaped_for_xml(stdout, opt->opts[i]);
255  fprintf(stdout, "</name>\n");
256  if (opt->descs && opt->opts[i] && opt->descs[i]) {
257  fprintf(stdout, "\t\t\t\t<description>");
258  print_escaped_for_xml(stdout, opt->descs[i]);
259  fprintf(stdout, "</description>\n");
260  }
261  fprintf(stdout, "\t\t\t</value>\n");
262  i++;
263  }
264  fprintf(stdout, "\t\t</values>\n");
265  }
266  if (opt->guisection) {
267  fprintf(stdout, "\t\t<guisection>\n\t\t\t");
268  print_escaped_for_xml(stdout, opt->guisection);
269  fprintf(stdout, "\n\t\t</guisection>\n");
270  }
271  if (opt->guidependency) {
272  fprintf(stdout, "\t\t<guidependency>\n\t\t\t");
273  print_escaped_for_xml(stdout, opt->guidependency);
274  fprintf(stdout, "\n\t\t</guidependency>\n");
275  }
276  /* TODO:
277  * - key_desc?
278  * - there surely are some more. which ones?
279  */
280 
281  opt = opt->next_opt;
282  fprintf(stdout, "\t</parameter>\n");
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(
329  stdout, _("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 
356 
357  fprintf(stdout, "</task>\n");
358 }
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
#define G_calloc(m, n)
Definition: defs/gis.h:95
#define G_alloca(n)
Definition: defs/gis.h:57
#define G_freea(p)
Definition: defs/gis.h:58
const char * G_program_name(void)
Return module name.
Definition: progrm_nme.c:28
#define TYPE_STRING
Definition: gis.h:186
#define YES
Definition: gis.h:187
#define TYPE_INTEGER
Definition: gis.h:184
#define FALSE
Definition: gis.h:83
#define TYPE_DOUBLE
Definition: gis.h:185
#define _(str)
Definition: glocale.h:10
char * dst
Definition: lz4.h:981
const char * src
Definition: lz4.h:989
void G__print_keywords(FILE *fd, void(*format)(FILE *, const char *), int newline)
Print list of keywords (internal use only)
Definition: parser.c:927
int G__uses_new_gisprompt(void)
Definition: parser.c:890
struct state * st
Definition: parser.c:104
void G__describe_option_rules_xml(FILE *fp)
Describe option rules in XML format (internal use only)
void G__usage_xml(void)
Print module usage description in XML format.
#define strcpy
Definition: parson.c:62
Structure that stores flag info.
Definition: gis.h:589
const char * guisection
Definition: gis.h:596
struct Flag * next_flag
Definition: gis.h:598
char suppress_required
Definition: gis.h:592
const char * description
Definition: gis.h:595
char key
Definition: gis.h:590
const char * label
Definition: gis.h:594
Structure that stores option information.
Definition: gis.h:558
const char * key
Definition: gis.h:559
struct Option * next_opt
Definition: gis.h:575
const char * key_desc
Definition: gis.h:565
const char ** opts
Definition: gis.h:564
const char * gisprompt
Definition: gis.h:576
const char * label
Definition: gis.h:566
int type
Definition: gis.h:560
const char * def
Definition: gis.h:573
const char * description
Definition: gis.h:567
int required
Definition: gis.h:561
const char ** descs
Definition: gis.h:570
const char * options
Definition: gis.h:563
int multiple
Definition: gis.h:562
const char * guisection
Definition: gis.h:577
const char * guidependency
Definition: gis.h:579