GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-299a28a7d0
parser_md_python.c
Go to the documentation of this file.
1 /*!
2  \file lib/gis/parser_md_python.c
3 
4  \brief GIS Library - Argument parsing functions (Markdown output - Python)
5 
6  (C) 2025 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 Vaclav Petras
12  */
13 #include <stdbool.h>
14 #include <stdio.h>
15 #include <string.h>
16 
17 #include <grass/gis.h>
18 #include <grass/glocale.h>
19 
20 #include "parser_local_proto.h"
21 
22 static void print_python_short_flag(FILE *file, const char *key,
23  const char *label, const char *description,
24  const char *indent);
25 static void print_python_long_flag(FILE *file, const char *key,
26  const char *label, const char *description,
27  const char *indent);
28 static void print_python_option(FILE *file, const struct Option *opt,
29  const char *indent);
30 static void print_python_example(FILE *file, const char *python_function,
31  const char *output_format_default,
32  const char *indent);
33 static void print_python_tuple(FILE *file, const char *type, int num_items);
34 
35 void print_python_short_flag(FILE *file, const char *key, const char *label,
36  const char *description, const char *indent)
37 {
38  fprintf(file, "%s", indent);
40  fprintf(file, "**%s**", key);
41  fprintf(file, MD_NEWLINE);
42  fprintf(file, "\n");
43  if (label != NULL) {
44  fprintf(file, "%s", indent);
45  G__md_print_escaped(file, "\t\t");
46  G__md_print_escaped(file, label);
47  fprintf(file, MD_NEWLINE);
48  fprintf(file, "\n");
49  }
50  if (description != NULL) {
51  fprintf(file, "%s", indent);
52  G__md_print_escaped(file, "\t\t");
53  G__md_print_escaped(file, description);
54  }
55 }
56 
57 void print_python_long_flag(FILE *file, const char *key, const char *label,
58  const char *description, const char *indent)
59 {
60  fprintf(file, "%s**%s**: bool, *optional*", indent, key);
61  fprintf(file, MD_NEWLINE);
62  fprintf(file, "\n");
63  if (label != NULL) {
64  fprintf(file, "%s", indent);
66  G__md_print_escaped(file, label);
67  fprintf(file, MD_NEWLINE);
68  fprintf(file, "\n");
69  }
70  if (description != NULL) {
71  fprintf(file, "%s", indent);
73  G__md_print_escaped(file, description);
74  fprintf(file, MD_NEWLINE);
75  fprintf(file, "\n");
76  }
77  fprintf(file, "%s", indent);
79  fprintf(file, "Default: *False*");
80 }
81 
82 void print_python_tuple(FILE *file, const char *type, int num_items)
83 {
84  fprintf(file, "tuple[%s", type);
85  for (int i = 1; i < num_items; i++) {
86  fprintf(file, ", %s", type);
87  }
88  fprintf(file, "]");
89 }
90 
91 void print_python_option(FILE *file, const struct Option *opt,
92  const char *indent)
93 {
94  const char *type;
95 
96  switch (opt->type) {
97  case TYPE_INTEGER:
98  type = "int";
99  break;
100  case TYPE_DOUBLE:
101  type = "float";
102  break;
103  case TYPE_STRING:
104  type = "str";
105  break;
106  default:
107  type = "str";
108  break;
109  }
110  fprintf(file, "%s**%s** : ", indent, opt->key);
111  int tuple_items = G__option_num_tuple_items(opt);
112  if (opt->multiple) {
113  if (tuple_items) {
114  fprintf(file, "list[");
115  print_python_tuple(file, type, tuple_items);
116  fprintf(file, "] | ");
117  print_python_tuple(file, type, tuple_items);
118  fprintf(file, " | list[%s] | str", type);
119  }
120  else {
121  if (strcmp(type, "str")) {
122  // If it is not a string, we also show it can be a string
123  // because that may be more relevant to show that for
124  // lists due to examples (it is possible for single value as
125  // well).
126  fprintf(file, "%s | list[%s] | str", type, type);
127  }
128  else {
129  fprintf(file, "%s | list[%s]", type, type);
130  }
131  }
132  }
133  else if (tuple_items) {
134  print_python_tuple(file, type, tuple_items);
135  fprintf(file, " | list[%s] | str", type);
136  }
137  else {
138  fprintf(file, "%s", type);
139  }
140  if (opt->required) {
141  fprintf(file, ", *required*");
142  }
143  else {
144  fprintf(file, ", *optional*");
145  }
146 
147  fprintf(file, MD_NEWLINE);
148  fprintf(file, "\n");
149  if (opt->label) {
150  fprintf(file, "%s", indent);
151  G__md_print_escaped(file, "\t");
153  }
154  if (opt->description) {
155  if (opt->label) {
156  fprintf(file, MD_NEWLINE);
157  fprintf(file, "\n");
158  }
159  fprintf(file, "%s", indent);
160  G__md_print_escaped(file, "\t");
162  }
163  if (opt->gisprompt || opt->key_desc) {
164  fprintf(file, MD_NEWLINE);
165  fprintf(file, "\n");
166  fprintf(file, "%s", indent);
167  G__md_print_escaped(file, "\t");
168  fprintf(file, "%s: ", _("Used as"));
169  }
170  if (opt->gisprompt) {
171  char age[KEYLENGTH];
172  char element[KEYLENGTH];
173  char desc[KEYLENGTH];
174  G__split_gisprompt(opt->gisprompt, age, element, desc);
175  if (strcmp(age, "new") == 0)
176  fprintf(file, "output, ");
177  else if (strcmp(age, "old") == 0)
178  fprintf(file, "input, ");
179  // While element more strictly expresses how the value will be
180  // used given that the parser may read that information, desc
181  // is meant as a user-facing representation of the same
182  // information.
183  fprintf(file, "%s", desc);
184  }
185  if (opt->gisprompt && opt->key_desc) {
186  fprintf(file, ", ");
187  }
188  if (opt->key_desc) {
189  fprintf(file, "*%s*", opt->key_desc);
190  }
191 
192  if (opt->options) {
193  fprintf(file, MD_NEWLINE);
194  fprintf(file, "\n");
195  fprintf(file, "%s", indent);
196  G__md_print_escaped(file, "\t");
197  fprintf(file, "%s: *", _("Allowed values"));
199  fprintf(file, "*");
200  }
201 
202  if (opt->descs) {
203  int i = 0;
204 
205  while (opt->opts[i]) {
206  if (opt->descs[i]) {
207  fprintf(file, MD_NEWLINE);
208  fprintf(file, "\n");
209  fprintf(file, "%s", indent);
210  char *thumbnails = NULL;
211  if (opt->gisprompt) {
212  if (strcmp(opt->gisprompt, "old,colortable,colortable") ==
213  0)
214  thumbnails = "colortables";
215  else if (strcmp(opt->gisprompt, "old,barscale,barscale") ==
216  0)
217  thumbnails = "barscales";
218  else if (strcmp(opt->gisprompt,
219  "old,northarrow,northarrow") == 0)
220  thumbnails = "northarrows";
221 
222  if (thumbnails) {
223  G__md_print_escaped(file, "\t\t");
224  fprintf(file, "![%s](%s/%s.png) ", opt->opts[i],
225  thumbnails, opt->opts[i]);
226  }
227  else {
228  G__md_print_escaped(file, "\t\t");
229  }
230  }
231  G__md_print_escaped(file, "\t");
232  fprintf(file, "**");
233  G__md_print_escaped(file, opt->opts[i]);
234  fprintf(file, "**: ");
235  G__md_print_escaped(file, opt->descs[i]);
236  }
237  i++;
238  }
239  }
240 
241  if (opt->def) {
242  fprintf(file, MD_NEWLINE);
243  fprintf(file, "\n");
244  fprintf(file, "%s", indent);
245  G__md_print_escaped(file, "\t");
246  fprintf(file, "%s:", _("Default"));
247  fprintf(file, " *");
249  fprintf(file, "*");
250  }
251 }
252 
253 void print_python_example(FILE *file, const char *python_function,
254  const char *output_format_default, const char *indent)
255 {
256  fprintf(file, "\n%sExample:\n", indent);
257 
258  fprintf(file, "\n%s```python\n", indent);
259  fprintf(file, "%sgs.%s(\"%s\"", indent, python_function, st->pgm_name);
260 
261  const struct Option *first_required_rule_option =
263  const struct Option *opt = NULL;
264  const char *type;
265 
266  if (st->n_opts) {
267  opt = &st->first_option;
268 
269  while (opt != NULL) {
270  if (opt->key_desc != NULL)
271  type = opt->key_desc;
272  else
273  switch (opt->type) {
274  case TYPE_INTEGER:
275  type = "integer";
276  break;
277  case TYPE_DOUBLE:
278  type = "float";
279  break;
280  case TYPE_STRING:
281  type = "string";
282  break;
283  default:
284  type = "string";
285  break;
286  }
287  if (opt->required || first_required_rule_option == opt) {
288  fprintf(file, ", %s=", opt->key);
289  if (output_format_default && strcmp(opt->key, "format") == 0) {
290  fprintf(file, "\"%s\"", output_format_default);
291  }
292  else if (opt->answer) {
293  if (opt->type == TYPE_INTEGER || opt->type == TYPE_DOUBLE) {
294  fprintf(file, "%s", opt->answer);
295  }
296  else {
297  fprintf(file, "\"%s\"", opt->answer);
298  }
299  }
300  else {
301  if (opt->type == TYPE_INTEGER || opt->type == TYPE_DOUBLE) {
302  fprintf(file, "%s", type);
303  }
304  else {
305  fprintf(file, "\"%s\"", type);
306  }
307  }
308  }
309  opt = opt->next_opt;
310  }
311  }
312  fprintf(file, ")\n%s```\n", indent);
313 }
314 
315 void G__md_print_python_short_version(FILE *file, const char *indent)
316 {
317  struct Option *opt;
318  struct Flag *flag;
319  int new_prompt = 0;
320  bool output_format_option = false;
321  const char *output_format_default = NULL;
322  bool shell_eval_flag = false;
323  const char *python_function = NULL;
324 
325  new_prompt = G__uses_new_gisprompt();
326 
327  if (st->n_opts) {
328  opt = &st->first_option;
329  while (opt != NULL) {
330  if (strcmp(opt->key, "format") == 0) {
331  if (opt->options) {
332  int i = 0;
333  while (opt->opts[i]) {
334  if (strcmp(opt->opts[i], "csv") == 0)
335  output_format_default = "csv";
336  if (strcmp(opt->opts[i], "json") == 0) {
337  output_format_default = "json";
338  break;
339  }
340  i++;
341  }
342  }
343  if (output_format_default) {
344  output_format_option = true;
345  }
346  break;
347  }
348  opt = opt->next_opt;
349  }
350  }
351  if (st->n_flags) {
352  flag = &st->first_flag;
353  while (st->n_flags && flag != NULL) {
354  if (flag->key == 'g') {
355  shell_eval_flag = true;
356  break;
357  }
358  flag = flag->next_flag;
359  }
360  }
361  if (output_format_option || (!new_prompt && shell_eval_flag)) {
362  python_function = "parse_command";
363  // We know this is can be parsed, but we can't detect just plain file
364  // because we can't distinguish between plain text outputs and
365  // modifications of data.
366  }
367  else {
368  python_function = "run_command";
369  }
370  fprintf(file, "%s*grass.script.%s*(\"***%s***\",", indent, python_function,
371  st->pgm_name);
372  fprintf(file, "\n");
373 
374  if (st->n_opts) {
375  opt = &st->first_option;
376 
377  while (opt != NULL) {
378  fprintf(file, "%s ", indent);
379  if (!opt->required && !opt->answer) {
380  fprintf(file, "**%s**=*None*", opt->key);
381  }
382  else {
383  fprintf(file, "**%s**", opt->key);
384  }
385  if (opt->answer) {
386  fprintf(file, "=");
387  int tuple_items = G__option_num_tuple_items(opt);
388  if (!tuple_items &&
389  (opt->type == TYPE_INTEGER || opt->type == TYPE_DOUBLE)) {
390  fprintf(file, "*");
392  fprintf(file, "*");
393  }
394  else {
395  fprintf(file, "*\"");
397  fprintf(file, "\"*");
398  }
399  }
400  fprintf(file, ",\n");
401 
402  opt = opt->next_opt;
403  }
404  }
405 
406  if (st->n_flags) {
407  flag = &st->first_flag;
408  fprintf(file, "%s **flags**=*None*,\n", indent);
409  }
410 
411  if (new_prompt)
412  fprintf(file, "%s **overwrite**=*False*,\n", indent);
413 
414  fprintf(file, "%s **verbose**=*False*,\n", indent);
415  fprintf(file, "%s **quiet**=*False*,\n", indent);
416  fprintf(file, "%s **superquiet**=*False*)\n", indent);
417 
418  print_python_example(file, python_function, output_format_default, indent);
419 }
420 
421 void G__md_print_python_long_version(FILE *file, const char *indent)
422 {
423  struct Option *opt;
424  struct Flag *flag;
425  int new_prompt = 0;
426 
427  new_prompt = G__uses_new_gisprompt();
428 
429  // Options (key-value parameters)
430  if (st->n_opts) {
431  opt = &st->first_option;
432  while (opt != NULL) {
433  print_python_option(file, opt, indent);
434  opt = opt->next_opt;
435  fprintf(file, MD_NEWLINE);
436  fprintf(file, "\n");
437  }
438  }
439 
440  // Short (one-letter) flags and tool-specific long flags
441  if (st->n_flags) {
442  fprintf(file, "%s**flags** : str, *optional*", indent);
443  fprintf(file, MD_NEWLINE);
444  fprintf(file, "\n");
445  fprintf(file, "%s", indent);
446  G__md_print_escaped(file, "\t");
447  fprintf(file, "Allowed values: ");
448  flag = &st->first_flag;
449  while (st->n_flags && flag != NULL) {
450  fprintf(file, "*%s*", &flag->key);
451  flag = flag->next_flag;
452  if (flag != NULL)
453  fprintf(file, ", ");
454  }
455  fprintf(file, MD_NEWLINE);
456  fprintf(file, "\n");
457  flag = &st->first_flag;
458  while (st->n_flags && flag != NULL) {
459  print_python_short_flag(file, &flag->key, flag->label,
460  flag->description, indent);
461  fprintf(file, MD_NEWLINE);
462  fprintf(file, "\n");
463  flag = flag->next_flag;
464  }
465  }
466  if (new_prompt) {
467  print_python_long_flag(
468  file, "overwrite", NULL,
469  _("Allow output files to overwrite existing files"), indent);
470  fprintf(file, MD_NEWLINE);
471  fprintf(file, "\n");
472  }
473  // Pre-defined long flags
474  print_python_long_flag(file, "verbose", NULL, _("Verbose module output"),
475  indent);
476  fprintf(file, MD_NEWLINE);
477  fprintf(file, "\n");
478  print_python_long_flag(file, "quiet", NULL, _("Quiet module output"),
479  indent);
480  fprintf(file, MD_NEWLINE);
481  fprintf(file, "\n");
482  print_python_long_flag(file, "superquiet", NULL,
483  _("Very quiet module output"), indent);
484  fprintf(file, MD_NEWLINE);
485  fprintf(file, "\n");
486 }
#define NULL
Definition: ccmath.h:32
#define TYPE_STRING
Definition: gis.h:185
#define TYPE_INTEGER
Definition: gis.h:183
#define TYPE_DOUBLE
Definition: gis.h:184
#define _(str)
Definition: glocale.h:10
#define file
int G__uses_new_gisprompt(void)
Definition: parser.c:893
struct state * st
Definition: parser.c:104
void G__split_gisprompt(const char *gisprompt, char *age, char *element, char *desc)
Definition: parser.c:1776
const struct Option * G__first_required_option_from_rules(void)
void G__md_print_escaped(FILE *f, const char *str)
int G__option_num_tuple_items(const struct Option *opt)
Get number of tuple items if option is a tuple.
void G__md_print_escaped_for_options(FILE *f, const char *str)
void G__md_print_python_long_version(FILE *file, const char *indent)
void G__md_print_python_short_version(FILE *file, const char *indent)
Structure that stores flag info.
Definition: gis.h:588
struct Flag * next_flag
Definition: gis.h:597
const char * description
Definition: gis.h:594
char key
Definition: gis.h:589
const char * label
Definition: gis.h:593
Structure that stores option information.
Definition: gis.h:557
const char * key
Definition: gis.h:558
struct Option * next_opt
Definition: gis.h:574
const char * key_desc
Definition: gis.h:564
const char ** opts
Definition: gis.h:563
const char * gisprompt
Definition: gis.h:575
const char * label
Definition: gis.h:565
int type
Definition: gis.h:559
const char * def
Definition: gis.h:572
const char * description
Definition: gis.h:566
char * answer
Definition: gis.h:571
int required
Definition: gis.h:560
const char ** descs
Definition: gis.h:569
const char * options
Definition: gis.h:562
int multiple
Definition: gis.h:561
Definition: lidar.h:85