GRASS GIS 8 Programmer's Manual 8.4.1(2025)-45ca3179ab
Loading...
Searching...
No Matches
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
23static void usage_rest_md(bool rest);
24static void print_flag(const char *key, const char *label,
25 const char *description, bool rest);
26void print_option(const struct Option *opt, bool rest, char *);
27static void print_escaped(FILE *f, const char *str, bool rest);
28static void print_escaped_for_rest(FILE *f, const char *str);
29static void print_escaped_for_md(FILE *f, const char *str);
30static void print_escaped_for_rest_options(FILE *f, const char *str);
31static 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 */
39void 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
277void 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
304void 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
459void 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
467void 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
481void 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
498void 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 */
513void 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*/
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}
void G_free(void *buf)
Free allocated memory.
Definition alloc.c:150
int G_asprintf(char **out, const char *fmt,...)
Definition asprintf.c:69
#define NULL
Definition ccmath.h:32
#define TRUE
Definition dbfopen.c:75
#define FALSE
Definition dbfopen.c:74
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
#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 *)
const char * G_program_name(void)
Return module name.
Definition progrm_nme.c:28
char * G_str_replace(const char *buffer, const char *old_str, const char *new_str)
Replace all occurrences of old_str in buffer with new_str.
Definition strings.c:189
char * G_store(const char *s)
Copy string to allocated memory.
Definition strings.c:87
void G_strip(char *buf)
Removes all leading and trailing white space from string.
Definition strings.c:300