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