GRASS GIS 8 Programmer's Manual  8.5.0dev(2024)-f622271e7a
parser_rest_md.c
Go to the documentation of this file.
1 /*!
2  \file lib/gis/parser_rest_md.c
3 
4  \brief GIS Library - Argument parsing functions (reStructuredText and
5  Markdown output)
6 
7  (C) 2012-2024 by the GRASS Development Team
8 
9  This program is free software under the GNU General Public License
10  (>=v2). Read the file COPYING that comes with GRASS for details.
11 
12  \author Luca Delucchi
13  \author Martin Landa (Markdown added)
14  */
15 #include <stdio.h>
16 #include <string.h>
17 
18 #include <grass/gis.h>
19 #include <grass/glocale.h>
20 
21 #include "parser_local_proto.h"
22 
23 #define MD_NEWLINE " "
24 
25 static void usage_rest_md(bool rest);
26 static void print_flag(const char *key, const char *label,
27  const char *description, bool rest);
28 void print_option(const struct Option *opt, bool rest, char *);
29 static void print_escaped(FILE *f, const char *str, bool rest);
30 static void print_escaped_for_rest(FILE *f, const char *str);
31 static void print_escaped_for_md(FILE *f, const char *str);
32 static void print_escaped_for_rest_options(FILE *f, const char *str);
33 static void print_escaped_for_md_keywords(FILE *f, const char *str);
34 
35 /*!
36  \brief Print module usage description in reStructuredText or in Markdown
37  format.
38 
39  \param bool rest TRUE for reStructuredText otherwise Markdown
40  */
41 void usage_rest_md(bool rest)
42 {
43  struct Option *opt;
44  struct Flag *flag;
45  const char *type;
46  int new_prompt = 0;
47 
48  new_prompt = G__uses_new_gisprompt();
49 
50  if (!st->pgm_name)
51  st->pgm_name = G_program_name();
52  if (!st->pgm_name)
53  st->pgm_name = "??";
54 
55  /* print metadata used by man/build*.py */
56  fprintf(stdout, "---\n");
57  fprintf(stdout, "name: %s\n", st->pgm_name);
58  fprintf(stdout, "description: %s\n", st->module_info.description);
59  fprintf(stdout, "keywords: ");
60  G__print_keywords(stdout, NULL, FALSE);
61  fprintf(stdout, "\n---\n\n");
62 
63  /* main header */
64  if (!rest)
65  fprintf(stdout, "# %s\n\n", st->pgm_name);
66 
67  /* header - GRASS module */
68  if (!rest)
69  fprintf(stdout, "## ");
70  fprintf(stdout, "%s\n", _("NAME"));
71  if (rest)
72  fprintf(stdout, "----");
73  fprintf(stdout, "\n");
74  fprintf(stdout, "***%s***", st->pgm_name);
75 
76  if (st->module_info.label || st->module_info.description)
77  fprintf(stdout, " - ");
78 
79  if (st->module_info.label)
80  fprintf(stdout, "%s\n", st->module_info.label);
81 
82  if (st->module_info.description) {
83  if (st->module_info.label)
84  fprintf(stdout, "\n");
85  fprintf(stdout, "%s\n", st->module_info.description);
86  }
87  fprintf(stdout, "\n");
88  if (!rest)
89  fprintf(stdout, "### ");
90  fprintf(stdout, "%s\n", _("KEYWORDS"));
91  if (rest)
92  fprintf(stdout, "--------\n");
93  fprintf(stdout, "\n");
94  if (st->module_info.keywords) {
95  if (rest) {
96  G__print_keywords(stdout, NULL, FALSE);
97  fprintf(stdout, "\n");
98  }
99  else {
100  G__print_keywords(stdout, print_escaped_for_md_keywords, TRUE);
101  }
102  }
103  fprintf(stdout, "\n");
104  if (!rest)
105  fprintf(stdout, "### ");
106  fprintf(stdout, "%s\n", _("SYNOPSIS"));
107  if (rest) {
108  fprintf(stdout, "--------\n\n");
109  fprintf(stdout, "| ");
110  }
111  else {
112  fprintf(stdout, "\n");
113  }
114  fprintf(stdout, "**%s**", st->pgm_name);
115  if (!rest)
116  fprintf(stdout, MD_NEWLINE);
117  fprintf(stdout, "\n");
118  if (rest)
119  fprintf(stdout, "| ");
120  fprintf(stdout, "**%s --help**", st->pgm_name);
121  if (!rest)
122  fprintf(stdout, MD_NEWLINE);
123  fprintf(stdout, "\n");
124  if (rest)
125  fprintf(stdout, "| ");
126  fprintf(stdout, "**%s**", st->pgm_name);
127 
128  /* print short version first */
129  if (st->n_flags) {
130  flag = &st->first_flag;
131  fprintf(stdout, " [**-");
132  while (flag != NULL) {
133  fprintf(stdout, "%c", flag->key);
134  flag = flag->next_flag;
135  }
136  fprintf(stdout, "**] ");
137  }
138  else
139  fprintf(stdout, " ");
140 
141  if (st->n_opts) {
142  opt = &st->first_option;
143 
144  while (opt != NULL) {
145  if (opt->key_desc != NULL)
146  type = opt->key_desc;
147  else
148  switch (opt->type) {
149  case TYPE_INTEGER:
150  type = "integer";
151  break;
152  case TYPE_DOUBLE:
153  type = "float";
154  break;
155  case TYPE_STRING:
156  type = "string";
157  break;
158  default:
159  type = "string";
160  break;
161  }
162  fprintf(stdout, " ");
163  if (!opt->required)
164  fprintf(stdout, "[");
165  fprintf(stdout, "**%s**=", opt->key);
166  if (rest)
167  fprintf(stdout, "\\ ");
168  fprintf(stdout, "*%s*", type);
169  if (opt->multiple) {
170  fprintf(stdout, " [,");
171  if (rest)
172  fprintf(stdout, "\\ ");
173  fprintf(stdout, "*%s*,...]", type);
174  }
175  if (!opt->required)
176  fprintf(stdout, "]");
177  if (rest)
178  fprintf(stdout, " ");
179  else
180  fprintf(stdout, "\n");
181 
182  opt = opt->next_opt;
183  }
184  }
185  if (new_prompt)
186  fprintf(stdout, " [**--overwrite**] ");
187 
188  fprintf(stdout, " [**--verbose**] ");
189  fprintf(stdout, " [**--quiet**] ");
190  fprintf(stdout, " [**--ui**]\n");
191 
192  /* now long version */
193  fprintf(stdout, "\n");
194  if (st->n_flags || new_prompt) {
195  flag = &st->first_flag;
196  if (!rest)
197  fprintf(stdout, "#### ");
198  fprintf(stdout, "%s\n", _("Flags"));
199  if (rest)
200  fprintf(stdout, "~~~~~~\n");
201  fprintf(stdout, "\n");
202  while (st->n_flags && flag != NULL) {
203  print_flag(&flag->key, flag->label, flag->description, rest);
204  if (!rest)
205  fprintf(stdout, MD_NEWLINE);
206  fprintf(stdout, "\n");
207  flag = flag->next_flag;
208  }
209  if (new_prompt) {
210  print_flag("overwrite", NULL,
211  _("Allow output files to overwrite existing files"),
212  rest);
213  if (!rest)
214  fprintf(stdout, MD_NEWLINE);
215  fprintf(stdout, "\n");
216  }
217  }
218  print_flag("help", NULL, _("Print usage summary"), rest);
219  if (!rest)
220  fprintf(stdout, MD_NEWLINE);
221  fprintf(stdout, "\n");
222  print_flag("verbose", NULL, _("Verbose module output"), rest);
223  if (!rest)
224  fprintf(stdout, MD_NEWLINE);
225  fprintf(stdout, "\n");
226  print_flag("quiet", NULL, _("Quiet module output"), rest);
227  if (!rest)
228  fprintf(stdout, MD_NEWLINE);
229  fprintf(stdout, "\n");
230  print_flag("ui", NULL, _("Force launching GUI dialog"), rest);
231  fprintf(stdout, "\n");
232 
233  if (st->n_opts) {
234  fprintf(stdout, "\n");
235  opt = &st->first_option;
236  if (!rest)
237  fprintf(stdout, "#### ");
238  fprintf(stdout, "%s\n", _("Parameters"));
239  if (rest)
240  fprintf(stdout, "~~~~~~~~~~~\n");
241  fprintf(stdout, "\n");
242  char image_spec_rest[GPATH_MAX];
243  image_spec_rest[0] = '\0';
244  while (opt != NULL) {
245  print_option(opt, rest, image_spec_rest);
246  opt = opt->next_opt;
247  if (opt != NULL) {
248  if (!rest)
249  fprintf(stdout, MD_NEWLINE);
250  }
251  fprintf(stdout, "\n");
252  }
253  if (strlen(image_spec_rest) > 0) {
254  fprintf(stdout, "\n");
255  fprintf(stdout, "%s", image_spec_rest);
256  }
257  }
258 }
259 
260 void print_flag(const char *key, const char *label, const char *description,
261  bool rest)
262 {
263  if (rest)
264  fprintf(stdout, "| ");
265  fprintf(stdout, "**");
266  if (strlen(key) > 1)
267  fprintf(stdout, "-");
268  fprintf(stdout, "-%s**", key);
269  if (!rest)
270  fprintf(stdout, MD_NEWLINE);
271  fprintf(stdout, "\n");
272  if (label != NULL) {
273  if (rest)
274  fprintf(stdout, "| ");
275  print_escaped(stdout, "\t", rest);
276  print_escaped(stdout, label, rest);
277  if (!rest)
278  fprintf(stdout, MD_NEWLINE);
279  fprintf(stdout, "\n");
280  }
281  if (description != NULL) {
282  if (rest)
283  fprintf(stdout, "| ");
284  print_escaped(stdout, "\t", rest);
285  print_escaped(stdout, description, rest);
286  }
287 }
288 
289 void print_option(const struct Option *opt, bool rest, char *image_spec_rest)
290 {
291  const char *type;
292 
293  /* TODO: make this a enumeration type? */
294  if (opt->key_desc != NULL)
295  type = opt->key_desc;
296  else
297  switch (opt->type) {
298  case TYPE_INTEGER:
299  type = "integer";
300  break;
301  case TYPE_DOUBLE:
302  type = "float";
303  break;
304  case TYPE_STRING:
305  type = "string";
306  break;
307  default:
308  type = "string";
309  break;
310  }
311 
312  if (rest)
313  fprintf(stdout, "| ");
314  fprintf(stdout, "**%s**=", opt->key);
315  if (rest)
316  fprintf(stdout, "\\ ");
317  fprintf(stdout, "*%s*", type);
318  if (opt->multiple) {
319  fprintf(stdout, " [,");
320  if (rest)
321  fprintf(stdout, "\\ ");
322  fprintf(stdout, "*%s*,...]", type);
323  }
324  /* fprintf(stdout, "*"); */
325  if (opt->required) {
326  fprintf(stdout, " **[required]**");
327  }
328  if (!rest)
329  fprintf(stdout, MD_NEWLINE);
330  fprintf(stdout, "\n");
331  if (opt->label) {
332  if (rest)
333  fprintf(stdout, "| ");
334  print_escaped(stdout, "\t", rest);
335  print_escaped(stdout, opt->label, rest);
336  }
337  if (opt->description) {
338  if (opt->label) {
339  if (!rest)
340  fprintf(stdout, MD_NEWLINE);
341  fprintf(stdout, "\n");
342  }
343  if (rest)
344  fprintf(stdout, "| ");
345  print_escaped(stdout, "\t", rest);
346  print_escaped(stdout, opt->description, rest);
347  }
348 
349  if (opt->options) {
350  if (!rest)
351  fprintf(stdout, MD_NEWLINE);
352  fprintf(stdout, "\n");
353  if (rest)
354  fprintf(stdout, "| ");
355  print_escaped(stdout, "\t", rest);
356  fprintf(stdout, "%s: *", _("Options"));
357  print_escaped_for_rest_options(stdout, opt->options);
358  fprintf(stdout, "*");
359  }
360 
361  if (opt->def) {
362  if (!rest)
363  fprintf(stdout, MD_NEWLINE);
364  fprintf(stdout, "\n");
365  if (rest)
366  fprintf(stdout, "| ");
367  print_escaped(stdout, "\t", rest);
368  fprintf(stdout, "%s:", _("Default"));
369  /* TODO check if value is empty
370  if (!opt->def.empty()){ */
371  fprintf(stdout, " *");
372  print_escaped(stdout, opt->def, rest);
373  fprintf(stdout, "*");
374  }
375 
376  if (opt->descs) {
377  int i = 0;
378 
379  while (opt->opts[i]) {
380  if (opt->descs[i]) {
381  if (!rest)
382  fprintf(stdout, MD_NEWLINE);
383  fprintf(stdout, "\n");
384  char *thumbnails = NULL;
385  if (opt->gisprompt) {
386  if (strcmp(opt->gisprompt, "old,colortable,colortable") ==
387  0)
388  thumbnails = "colortables";
389  else if (strcmp(opt->gisprompt, "old,barscale,barscale") ==
390  0)
391  thumbnails = "barscales";
392  else if (strcmp(opt->gisprompt,
393  "old,northarrow,northarrow") == 0)
394  thumbnails = "northarrows";
395 
396  if (thumbnails) {
397  if (rest) {
398  char *image_spec;
399  G_asprintf(&image_spec,
400  ".. |%s| image:: %s/%s.png\n",
401  opt->opts[i], thumbnails, opt->opts[i]);
402  strcat(image_spec_rest, image_spec);
403  }
404  else {
405  print_escaped(stdout, "\t\t", rest);
406  fprintf(stdout, "![%s](%s/%s.png) ", opt->opts[i],
407  thumbnails, opt->opts[i]);
408  }
409  }
410  else {
411  if (rest)
412  fprintf(stdout, "| ");
413  print_escaped(stdout, "\t\t", rest);
414  if (rest)
415  fprintf(stdout, "\\ ");
416  }
417  }
418 
419  if (rest && thumbnails) {
420  fprintf(stdout, "| ");
421  print_escaped(stdout, "\t\t", rest);
422  fprintf(stdout, "|%s| ", opt->opts[i]);
423  }
424  if (!rest)
425  print_escaped(stdout, "\t", rest);
426  fprintf(stdout, "**");
427  print_escaped(stdout, opt->opts[i], rest);
428  fprintf(stdout, "**: ");
429  print_escaped(stdout, opt->descs[i], rest);
430  }
431  i++;
432  }
433  }
434 }
435 
436 /*!
437  * \brief Format text for reStructuredText output
438  */
439 #define do_escape(c, escaped) \
440  case c: \
441  fputs(escaped, f); \
442  break
443 
444 void print_escaped(FILE *f, const char *str, bool rest)
445 {
446  if (rest)
447  print_escaped_for_rest(f, str);
448  else
449  print_escaped_for_md(f, str);
450 }
451 
452 void print_escaped_for_rest(FILE *f, const char *str)
453 {
454  const char *s;
455 
456  for (s = str; *s; s++) {
457  switch (*s) {
458  do_escape('\n', "\n\n");
459  do_escape('\t', " ");
460  default:
461  fputc(*s, f);
462  }
463  }
464 }
465 
466 void print_escaped_for_md(FILE *f, const char *str)
467 {
468  const char *s;
469 
470  for (s = str; *s; s++) {
471  switch (*s) {
472  do_escape('\n', "\\\n");
473  do_escape('\t', "&nbsp;&nbsp;&nbsp;&nbsp;");
474  do_escape('<', "&lt;");
475  do_escape('>', "&gt;");
476  do_escape('*', "\\*");
477  default:
478  fputc(*s, f);
479  }
480  }
481 }
482 
483 void print_escaped_for_rest_options(FILE *f, const char *str)
484 {
485  const char *s;
486 
487  for (s = str; *s; s++) {
488  switch (*s) {
489  do_escape('\n', "\n\n");
490  do_escape(',', ", ");
491  default:
492  fputc(*s, f);
493  }
494  }
495 }
496 
497 /* generate HTML links */
498 void print_escaped_for_md_keywords(FILE *f, const char *str)
499 {
500  /* removes all leading and trailing white space from keyword
501  string, as spotted in Japanese and other locales. */
502  char *str_s;
503  str_s = G_store(str);
504  G_strip(str_s);
505 
506  /* HTML link only for second keyword = topic */
507  if (st->n_keys > 1 && strcmp(st->module_info.keywords[1], str) == 0) {
508 
509  const char *s;
510 
511  /* TODO: fprintf(f, _("topic: ")); */
512  fprintf(f, "[%s](topic_", str_s);
513  for (s = str_s; *s; s++) {
514  switch (*s) {
515  do_escape(' ', "_");
516  default:
517  fputc(*s, f);
518  }
519  }
520  fprintf(f, ".md)");
521  }
522  else { /* first and other than second keyword */
523  if (st->n_keys > 0 && strcmp(st->module_info.keywords[0], str) == 0) {
524  /* command family */
525  const char *s;
526 
527  fprintf(f, "[%s](", str_s);
528  for (s = str_s; *s; s++) {
529  switch (*s) {
530  do_escape(' ', "_");
531  default:
532  fputc(*s, f);
533  }
534  }
535  fprintf(f, ".md)");
536  }
537  else {
538  /* keyword index, mkdocs expects dash */
539  char *str_link;
540  str_link = G_str_replace(str_s, " ", "-");
541  G_str_to_lower(str_link);
542  fprintf(f, "[%s](keywords.md#%s)", str_s, str_link);
543  G_free(str_link);
544  }
545  }
546 
547  G_free(str_s);
548 }
549 
550 #undef do_escape
551 
552 /*!
553  \brief Print module usage description in reStructuredText format.
554 */
555 void G__usage_rest(void)
556 {
557  usage_rest_md(TRUE);
558 }
559 
560 /*!
561  \brief Print module usage description in Markdown format.
562 */
564 {
565  usage_rest_md(FALSE);
566 }
#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
int G_asprintf(char **, const char *,...) __attribute__((format(printf
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 GPATH_MAX
Definition: gis.h:194
#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 reStructuredText output.
void G__usage_markdown(void)
Print module usage description in Markdown format.
void G__usage_rest(void)
Print module usage description in reStructuredText format.
void print_option(const struct Option *opt, bool rest, char *)
#define MD_NEWLINE
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
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