GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-c7eacfc3b0
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  (strcmp(opt->key, "format") == 0 && output_format_default)) {
289  fprintf(file, ", %s=", opt->key);
290  if (output_format_default && strcmp(opt->key, "format") == 0) {
291  fprintf(file, "\"%s\"", output_format_default);
292  }
293  else if (opt->answer) {
294  if (opt->type == TYPE_INTEGER || opt->type == TYPE_DOUBLE) {
295  fprintf(file, "%s", opt->answer);
296  }
297  else {
298  fprintf(file, "\"%s\"", opt->answer);
299  }
300  }
301  else {
302  if (opt->type == TYPE_INTEGER) {
303  fprintf(file, "0");
304  }
305  else if (opt->type == TYPE_DOUBLE) {
306  fprintf(file, "0.0");
307  }
308  else {
309  fprintf(file, "\"%s\"", type);
310  }
311  }
312  }
313  opt = opt->next_opt;
314  }
315  }
316  fprintf(file, ")\n%s```\n", indent);
317 }
318 
319 void G__md_print_python_short_version(FILE *file, const char *indent)
320 {
321  struct Option *opt;
322  struct Flag *flag;
323  int new_prompt = 0;
324  bool output_format_option = false;
325  const char *output_format_default = NULL;
326  bool shell_eval_flag = false;
327  const char *python_function = NULL;
328 
329  new_prompt = G__uses_new_gisprompt();
330 
331  if (st->n_opts) {
332  opt = &st->first_option;
333  while (opt != NULL) {
334  if (strcmp(opt->key, "format") == 0) {
335  if (opt->options) {
336  int i = 0;
337  while (opt->opts[i]) {
338  if (strcmp(opt->opts[i], "csv") == 0)
339  output_format_default = "csv";
340  if (strcmp(opt->opts[i], "json") == 0) {
341  output_format_default = "json";
342  break;
343  }
344  i++;
345  }
346  }
347  if (output_format_default) {
348  output_format_option = true;
349  }
350  break;
351  }
352  opt = opt->next_opt;
353  }
354  }
355  if (st->n_flags) {
356  flag = &st->first_flag;
357  while (st->n_flags && flag != NULL) {
358  if (flag->key == 'g') {
359  shell_eval_flag = true;
360  break;
361  }
362  flag = flag->next_flag;
363  }
364  }
365  if (output_format_option || (!new_prompt && shell_eval_flag)) {
366  python_function = "parse_command";
367  // We know this is can be parsed, but we can't detect just plain file
368  // because we can't distinguish between plain text outputs and
369  // modifications of data.
370  }
371  else {
372  python_function = "run_command";
373  }
374  fprintf(file, "%s*grass.script.%s*(\"***%s***\",", indent, python_function,
375  st->pgm_name);
376  fprintf(file, "\n");
377 
378  if (st->n_opts) {
379  opt = &st->first_option;
380 
381  while (opt != NULL) {
382  fprintf(file, "%s ", indent);
383  if (!opt->required && !opt->answer) {
384  fprintf(file, "**%s**=*None*", opt->key);
385  }
386  else {
387  fprintf(file, "**%s**", opt->key);
388  }
389  if (opt->answer) {
390  fprintf(file, "=");
391  int tuple_items = G__option_num_tuple_items(opt);
392  if (!tuple_items &&
393  (opt->type == TYPE_INTEGER || opt->type == TYPE_DOUBLE)) {
394  fprintf(file, "*");
396  fprintf(file, "*");
397  }
398  else {
399  fprintf(file, "*\"");
401  fprintf(file, "\"*");
402  }
403  }
404  fprintf(file, ",\n");
405 
406  opt = opt->next_opt;
407  }
408  }
409 
410  if (st->n_flags) {
411  flag = &st->first_flag;
412  fprintf(file, "%s **flags**=*None*,\n", indent);
413  }
414 
415  if (new_prompt)
416  fprintf(file, "%s **overwrite**=*False*,\n", indent);
417 
418  fprintf(file, "%s **verbose**=*False*,\n", indent);
419  fprintf(file, "%s **quiet**=*False*,\n", indent);
420  fprintf(file, "%s **superquiet**=*False*)\n", indent);
421 
422  print_python_example(file, python_function, output_format_default, indent);
423 }
424 
425 void G__md_print_python_long_version(FILE *file, const char *indent)
426 {
427  struct Option *opt;
428  struct Flag *flag;
429  int new_prompt = 0;
430 
431  new_prompt = G__uses_new_gisprompt();
432 
433  // Options (key-value parameters)
434  if (st->n_opts) {
435  opt = &st->first_option;
436  while (opt != NULL) {
437  print_python_option(file, opt, indent);
438  opt = opt->next_opt;
439  fprintf(file, MD_NEWLINE);
440  fprintf(file, "\n");
441  }
442  }
443 
444  // Short (one-letter) flags and tool-specific long flags
445  if (st->n_flags) {
446  fprintf(file, "%s**flags** : str, *optional*", indent);
447  fprintf(file, MD_NEWLINE);
448  fprintf(file, "\n");
449  fprintf(file, "%s", indent);
450  G__md_print_escaped(file, "\t");
451  fprintf(file, "Allowed values: ");
452  flag = &st->first_flag;
453  while (st->n_flags && flag != NULL) {
454  fprintf(file, "*%s*", &flag->key);
455  flag = flag->next_flag;
456  if (flag != NULL)
457  fprintf(file, ", ");
458  }
459  fprintf(file, MD_NEWLINE);
460  fprintf(file, "\n");
461  flag = &st->first_flag;
462  while (st->n_flags && flag != NULL) {
463  print_python_short_flag(file, &flag->key, flag->label,
464  flag->description, indent);
465  fprintf(file, MD_NEWLINE);
466  fprintf(file, "\n");
467  flag = flag->next_flag;
468  }
469  }
470  if (new_prompt) {
471  print_python_long_flag(
472  file, "overwrite", NULL,
473  _("Allow output files to overwrite existing files"), indent);
474  fprintf(file, MD_NEWLINE);
475  fprintf(file, "\n");
476  }
477  // Pre-defined long flags
478  print_python_long_flag(file, "verbose", NULL, _("Verbose module output"),
479  indent);
480  fprintf(file, MD_NEWLINE);
481  fprintf(file, "\n");
482  print_python_long_flag(file, "quiet", NULL, _("Quiet module output"),
483  indent);
484  fprintf(file, MD_NEWLINE);
485  fprintf(file, "\n");
486  print_python_long_flag(file, "superquiet", NULL,
487  _("Very quiet module output"), indent);
488  fprintf(file, MD_NEWLINE);
489  fprintf(file, "\n");
490 }
#define NULL
Definition: ccmath.h:32
#define TYPE_STRING
Definition: gis.h:191
#define TYPE_INTEGER
Definition: gis.h:189
#define TYPE_DOUBLE
Definition: gis.h:190
#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:594
struct Flag * next_flag
Definition: gis.h:603
const char * description
Definition: gis.h:600
char key
Definition: gis.h:595
const char * label
Definition: gis.h:599
Structure that stores option information.
Definition: gis.h:563
const char * key
Definition: gis.h:564
struct Option * next_opt
Definition: gis.h:580
const char * key_desc
Definition: gis.h:570
const char ** opts
Definition: gis.h:569
const char * gisprompt
Definition: gis.h:581
const char * label
Definition: gis.h:571
int type
Definition: gis.h:565
const char * def
Definition: gis.h:578
const char * description
Definition: gis.h:572
char * answer
Definition: gis.h:577
int required
Definition: gis.h:566
const char ** descs
Definition: gis.h:575
const char * options
Definition: gis.h:568
int multiple
Definition: gis.h:567
Definition: lidar.h:85