GRASS GIS 8 Programmer's Manual  8.5.0dev(2025)-565e82de51
All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
parser_md.c
Go to the documentation of this file.
1 /*!
2  \file lib/gis/parser_md.c
3 
4  \brief GIS Library - Argument parsing functions (Markdown output)
5 
6  (C) 2012-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 Martin Landa
12  */
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include <grass/gis.h>
17 #include <grass/glocale.h>
18 
19 #include "parser_local_proto.h"
20 
21 #define MD_NEWLINE " "
22 
23 static void print_flag(const char *key, const char *label,
24  const char *description);
25 void print_option(const struct Option *opt);
26 static void print_escaped(FILE *f, const char *str);
27 static void print_escaped_for_md(FILE *f, const char *str);
28 static void print_escaped_for_md_keywords(FILE *f, const char *str);
29 static void print_escaped_for_md_options(FILE *f, const char *str);
30 
31 /*!
32  \brief Print module usage description in Markdown format.
33  */
35 {
36  struct Option *opt;
37  struct Flag *flag;
38  const char *type;
39  int new_prompt = 0;
40 
41  new_prompt = G__uses_new_gisprompt();
42 
43  if (!st->pgm_name)
44  st->pgm_name = G_program_name();
45  if (!st->pgm_name)
46  st->pgm_name = "??";
47 
48  /* print metadata used by man/build*.py */
49  fprintf(stdout, "---\n");
50  fprintf(stdout, "name: %s\n", st->pgm_name);
51  fprintf(stdout, "description: %s\n", st->module_info.description);
52  fprintf(stdout, "keywords: [ ");
53  G__print_keywords(stdout, NULL, FALSE);
54  fprintf(stdout, " ]");
55  fprintf(stdout, "\n---\n\n");
56 
57  /* main header */
58  fprintf(stdout, "# %s\n\n", st->pgm_name);
59 
60  /* header - GRASS module */
61  fprintf(stdout, "## ");
62  fprintf(stdout, "%s\n", _("NAME"));
63  fprintf(stdout, "\n");
64  fprintf(stdout, "***%s***", st->pgm_name);
65 
66  if (st->module_info.label || st->module_info.description)
67  fprintf(stdout, " - ");
68 
69  if (st->module_info.label)
70  fprintf(stdout, "%s\n", st->module_info.label);
71 
72  if (st->module_info.description) {
73  if (st->module_info.label)
74  fprintf(stdout, "\n");
75  fprintf(stdout, "%s\n", st->module_info.description);
76  }
77  fprintf(stdout, "\n");
78  fprintf(stdout, "### ");
79  fprintf(stdout, "%s\n", _("KEYWORDS"));
80  fprintf(stdout, "\n");
81  if (st->module_info.keywords) {
82  G__print_keywords(stdout, print_escaped_for_md_keywords, TRUE);
83  }
84  fprintf(stdout, "\n");
85  fprintf(stdout, "### ");
86  fprintf(stdout, "%s\n", _("SYNOPSIS"));
87  fprintf(stdout, "\n");
88  fprintf(stdout, "**%s**", st->pgm_name);
89  fprintf(stdout, MD_NEWLINE);
90  fprintf(stdout, "\n");
91  fprintf(stdout, "**%s --help**", st->pgm_name);
92  fprintf(stdout, MD_NEWLINE);
93  fprintf(stdout, "\n");
94  fprintf(stdout, "**%s**", st->pgm_name);
95 
96  /* print short version first */
97  if (st->n_flags) {
98  flag = &st->first_flag;
99  fprintf(stdout, " [**-");
100  while (flag != NULL) {
101  fprintf(stdout, "%c", flag->key);
102  flag = flag->next_flag;
103  }
104  fprintf(stdout, "**] ");
105  }
106  else
107  fprintf(stdout, " ");
108 
109  if (st->n_opts) {
110  opt = &st->first_option;
111 
112  while (opt != NULL) {
113  if (opt->key_desc != NULL)
114  type = opt->key_desc;
115  else
116  switch (opt->type) {
117  case TYPE_INTEGER:
118  type = "integer";
119  break;
120  case TYPE_DOUBLE:
121  type = "float";
122  break;
123  case TYPE_STRING:
124  type = "string";
125  break;
126  default:
127  type = "string";
128  break;
129  }
130  fprintf(stdout, " ");
131  if (!opt->required)
132  fprintf(stdout, "[");
133  fprintf(stdout, "**%s**=", opt->key);
134  fprintf(stdout, "*%s*", type);
135  if (opt->multiple) {
136  fprintf(stdout, " [,");
137  fprintf(stdout, "*%s*,...]", type);
138  }
139  if (!opt->required)
140  fprintf(stdout, "]");
141  fprintf(stdout, "\n");
142 
143  opt = opt->next_opt;
144  }
145  }
146  if (new_prompt)
147  fprintf(stdout, " [**--overwrite**] ");
148 
149  fprintf(stdout, " [**--verbose**] ");
150  fprintf(stdout, " [**--quiet**] ");
151  fprintf(stdout, " [**--ui**]\n");
152 
153  /* now long version */
154  fprintf(stdout, "\n");
155  if (st->n_flags || new_prompt) {
156  flag = &st->first_flag;
157  fprintf(stdout, "#### ");
158  fprintf(stdout, "%s\n", _("Flags"));
159  fprintf(stdout, "\n");
160  while (st->n_flags && flag != NULL) {
161  print_flag(&flag->key, flag->label, flag->description);
162  fprintf(stdout, MD_NEWLINE);
163  fprintf(stdout, "\n");
164  flag = flag->next_flag;
165  }
166  if (new_prompt) {
167  print_flag("overwrite", NULL,
168  _("Allow output files to overwrite existing files"));
169  fprintf(stdout, MD_NEWLINE);
170  fprintf(stdout, "\n");
171  }
172  }
173  print_flag("help", NULL, _("Print usage summary"));
174  fprintf(stdout, MD_NEWLINE);
175  fprintf(stdout, "\n");
176  print_flag("verbose", NULL, _("Verbose module output"));
177  fprintf(stdout, MD_NEWLINE);
178  fprintf(stdout, "\n");
179  print_flag("quiet", NULL, _("Quiet module output"));
180  fprintf(stdout, MD_NEWLINE);
181  fprintf(stdout, "\n");
182  print_flag("ui", NULL, _("Force launching GUI dialog"));
183  fprintf(stdout, "\n");
184 
185  if (st->n_opts) {
186  fprintf(stdout, "\n");
187  opt = &st->first_option;
188  fprintf(stdout, "#### ");
189  fprintf(stdout, "%s\n", _("Parameters"));
190  fprintf(stdout, "\n");
191  while (opt != NULL) {
192  print_option(opt);
193  opt = opt->next_opt;
194  if (opt != NULL) {
195  fprintf(stdout, MD_NEWLINE);
196  }
197  fprintf(stdout, "\n");
198  }
199  }
200 }
201 
202 void print_flag(const char *key, const char *label, const char *description)
203 {
204  fprintf(stdout, "**");
205  if (strlen(key) > 1)
206  fprintf(stdout, "-");
207  fprintf(stdout, "-%s**", key);
208  fprintf(stdout, MD_NEWLINE);
209  fprintf(stdout, "\n");
210  if (label != NULL) {
211  print_escaped(stdout, "\t");
212  print_escaped(stdout, label);
213  fprintf(stdout, MD_NEWLINE);
214  fprintf(stdout, "\n");
215  }
216  if (description != NULL) {
217  print_escaped(stdout, "\t");
218  print_escaped(stdout, description);
219  }
220 }
221 
222 void print_option(const struct Option *opt)
223 {
224  const char *type;
225 
226  /* TODO: make this a enumeration type? */
227  if (opt->key_desc != NULL)
228  type = opt->key_desc;
229  else
230  switch (opt->type) {
231  case TYPE_INTEGER:
232  type = "integer";
233  break;
234  case TYPE_DOUBLE:
235  type = "float";
236  break;
237  case TYPE_STRING:
238  type = "string";
239  break;
240  default:
241  type = "string";
242  break;
243  }
244  fprintf(stdout, "**%s**=", opt->key);
245  fprintf(stdout, "*%s*", type);
246  if (opt->multiple) {
247  fprintf(stdout, " [,");
248  fprintf(stdout, "*%s*,...]", type);
249  }
250  /* fprintf(stdout, "*"); */
251  if (opt->required) {
252  fprintf(stdout, " **[required]**");
253  }
254  fprintf(stdout, MD_NEWLINE);
255  fprintf(stdout, "\n");
256  if (opt->label) {
257  print_escaped(stdout, "\t");
258  print_escaped(stdout, opt->label);
259  }
260  if (opt->description) {
261  if (opt->label) {
262  fprintf(stdout, MD_NEWLINE);
263  fprintf(stdout, "\n");
264  }
265  print_escaped(stdout, "\t");
266  print_escaped(stdout, opt->description);
267  }
268 
269  if (opt->options) {
270  fprintf(stdout, MD_NEWLINE);
271  fprintf(stdout, "\n");
272  print_escaped(stdout, "\t");
273  fprintf(stdout, "%s: *", _("Options"));
274  print_escaped_for_md_options(stdout, opt->options);
275  fprintf(stdout, "*");
276  }
277 
278  if (opt->def) {
279  fprintf(stdout, MD_NEWLINE);
280  fprintf(stdout, "\n");
281  print_escaped(stdout, "\t");
282  fprintf(stdout, "%s:", _("Default"));
283  /* TODO check if value is empty
284  if (!opt->def.empty()){ */
285  fprintf(stdout, " *");
286  print_escaped(stdout, opt->def);
287  fprintf(stdout, "*");
288  }
289 
290  if (opt->descs) {
291  int i = 0;
292 
293  while (opt->opts[i]) {
294  if (opt->descs[i]) {
295  fprintf(stdout, MD_NEWLINE);
296  fprintf(stdout, "\n");
297  char *thumbnails = NULL;
298  if (opt->gisprompt) {
299  if (strcmp(opt->gisprompt, "old,colortable,colortable") ==
300  0)
301  thumbnails = "colortables";
302  else if (strcmp(opt->gisprompt, "old,barscale,barscale") ==
303  0)
304  thumbnails = "barscales";
305  else if (strcmp(opt->gisprompt,
306  "old,northarrow,northarrow") == 0)
307  thumbnails = "northarrows";
308 
309  if (thumbnails) {
310  print_escaped(stdout, "\t\t");
311  fprintf(stdout, "![%s](%s/%s.png) ", opt->opts[i],
312  thumbnails, opt->opts[i]);
313  }
314  else {
315  print_escaped(stdout, "\t\t");
316  }
317  }
318  print_escaped(stdout, "\t");
319  fprintf(stdout, "**");
320  print_escaped(stdout, opt->opts[i]);
321  fprintf(stdout, "**: ");
322  print_escaped(stdout, opt->descs[i]);
323  }
324  i++;
325  }
326  }
327 }
328 
329 /*!
330  * \brief Format text for Markdown output
331  */
332 #define do_escape(c, escaped) \
333  case c: \
334  fputs(escaped, f); \
335  break
336 
337 void print_escaped(FILE *f, const char *str)
338 {
339  print_escaped_for_md(f, str);
340 }
341 
342 void print_escaped_for_md(FILE *f, const char *str)
343 {
344  const char *s;
345 
346  for (s = str; *s; s++) {
347  switch (*s) {
348  do_escape('\n', "\\\n");
349  do_escape('\t', "&nbsp;&nbsp;&nbsp;&nbsp;");
350  do_escape('<', "&lt;");
351  do_escape('>', "&gt;");
352  do_escape('*', "\\*");
353  default:
354  fputc(*s, f);
355  }
356  }
357 }
358 
359 void print_escaped_for_md_options(FILE *f, const char *str)
360 {
361  const char *s;
362 
363  for (s = str; *s; s++) {
364  switch (*s) {
365  do_escape('\n', "\n\n");
366  do_escape(',', ", ");
367  default:
368  fputc(*s, f);
369  }
370  }
371 }
372 
373 /* generate HTML links */
374 void print_escaped_for_md_keywords(FILE *f, const char *str)
375 {
376  /* removes all leading and trailing white space from keyword
377  string, as spotted in Japanese and other locales. */
378  char *str_s;
379  str_s = G_store(str);
380  G_strip(str_s);
381 
382  /* HTML link only for second keyword = topic */
383  if (st->n_keys > 1 && strcmp(st->module_info.keywords[1], str) == 0) {
384 
385  const char *s;
386 
387  /* TODO: fprintf(f, _("topic: ")); */
388  fprintf(f, "[%s](topic_", str_s);
389  for (s = str_s; *s; s++) {
390  switch (*s) {
391  do_escape(' ', "_");
392  default:
393  fputc(*s, f);
394  }
395  }
396  fprintf(f, ".md)");
397  }
398  else { /* first and other than second keyword */
399  if (st->n_keys > 0 && strcmp(st->module_info.keywords[0], str) == 0) {
400  /* command family */
401  const char *s;
402 
403  fprintf(f, "[%s](", str_s);
404  for (s = str_s; *s; s++) {
405  switch (*s) {
406  do_escape(' ', "_");
407  default:
408  fputc(*s, f);
409  }
410  }
411  fprintf(f, ".md)");
412  }
413  else {
414  /* keyword index, mkdocs expects dash */
415  char *str_link;
416  str_link = G_str_replace(str_s, " ", "-");
417  G_str_to_lower(str_link);
418  fprintf(f, "[%s](keywords.md#%s)", str_s, str_link);
419  G_free(str_link);
420  }
421  }
422 
423  G_free(str_s);
424 }
425 
426 #undef do_escape
#define NULL
Definition: ccmath.h:32
void G_free(void *)
Free allocated memory.
Definition: gis/alloc.c:150
char * G_str_replace(const char *, const char *, const char *)
Replace all occurrences of old_str in buffer with new_str.
Definition: strings.c:189
void G_strip(char *)
Removes all leading and trailing white space from string.
Definition: strings.c:300
void G_str_to_lower(char *)
Convert string to lower case.
Definition: strings.c:383
const char * G_program_name(void)
Return module name.
Definition: progrm_nme.c:28
char * G_store(const char *)
Copy string to allocated memory.
Definition: strings.c:87
#define TYPE_STRING
Definition: gis.h:186
#define TYPE_INTEGER
Definition: gis.h:184
#define TRUE
Definition: gis.h:79
#define FALSE
Definition: gis.h:83
#define TYPE_DOUBLE
Definition: gis.h:185
#define _(str)
Definition: glocale.h:10
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
#define do_escape(c, escaped)
Format text for Markdown output.
Definition: parser_md.c:332
void G__usage_markdown(void)
Print module usage description in Markdown format.
Definition: parser_md.c:34
void print_option(const struct Option *opt)
Definition: parser_md.c:222
#define MD_NEWLINE
Definition: parser_md.c:21
Structure that stores flag info.
Definition: gis.h:589
struct Flag * next_flag
Definition: gis.h:598
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