GRASS GIS 8 Programmer's Manual 8.2.1(2023)-exported
parser_wps.c
Go to the documentation of this file.
1
2#include <stdio.h>
3#include <stdlib.h>
4#include <string.h>
5#include <ctype.h>
6
7#include <grass/config.h>
8#include <grass/gis.h>
9#include <grass/glocale.h>
10
11#if defined(HAVE_LANGINFO_H)
12#include <langinfo.h>
13#endif
14#if defined(__MINGW32__) && defined(USE_NLS)
15#include <localcharset.h>
16#endif
17
18#include "parser_local_proto.h"
19
20/* Defines and prototypes for WPS process_description XML document generation
21 */
22#define TYPE_OTHER -1
23#define TYPE_RASTER 0
24#define TYPE_VECTOR 1
25#define TYPE_PLAIN_TEXT 2
26#define TYPE_RANGE 3
27#define TYPE_LIST 4
28#define TYPE_STDS 5 /* Space time datasets of type raster, raster3d and vector */
29#define TYPE_STRDS 6 /* Space time raster datasets */
30#define TYPE_STVDS 7 /* Space time vector datasets */
31#define WPS_INPUT 0
32#define WPS_OUTPUT 1
33
34static void wps_print_mimetype_text_plain(void);
35static void wps_print_mimetype_raster_tiff(void);
36static void wps_print_mimetype_raster_tiff_other(void);
37static void wps_print_mimetype_raster_png(void);
38static void wps_print_mimetype_raster_gif(void);
39static void wps_print_mimetype_raster_jpeg(void);
40static void wps_print_mimetype_raster_hfa(void);
41static void wps_print_mimetype_raster_netCDF(void);
42static void wps_print_mimetype_raster_netCDF_other(void);
43static void wps_print_mimetype_raster_grass_binary(void);
44static void wps_print_mimetype_raster_grass_ascii(void);
45static void wps_print_mimetype_vector_gml311(void);
46static void wps_print_mimetype_vector_gml311_appl(void);
47static void wps_print_mimetype_vector_gml212(void);
48static void wps_print_mimetype_vector_gml212_appl(void);
49static void wps_print_mimetype_vector_kml22(void);
50static void wps_print_mimetype_vector_dgn(void);
51static void wps_print_mimetype_vector_shape(void);
52static void wps_print_mimetype_vector_zipped_shape(void);
53static void wps_print_mimetype_vector_grass_ascii(void);
54static void wps_print_mimetype_vector_grass_binary(void);
55static void wps_print_mimetype_space_time_datasets(void);
56static void wps_print_mimetype_space_time_raster_datasets(void);
57static void wps_print_mimetype_space_time_vector_datasets(void);
58static void wps_print_mimetype_space_time_vector_datasets_tar(void);
59static void wps_print_mimetype_space_time_raster_datasets_tar(void);
60static void wps_print_mimetype_space_time_vector_datasets_tar_gz(void);
61static void wps_print_mimetype_space_time_raster_datasets_tar_gz(void);
62static void wps_print_mimetype_space_time_vector_datasets_tar_bz2(void);
63static void wps_print_mimetype_space_time_raster_datasets_tar_bz2(void);
64
65static void wps_print_process_descriptions_begin(void);
66static void wps_print_process_descriptions_end(void);
67static void wps_print_process_description_begin(int , int , const char *, const char *, const char *, const char **, int );
68static void wps_print_process_description_end(void);
69static void wps_print_data_inputs_begin(void);
70static void wps_print_data_inputs_end(void);
71static void wps_print_process_outputs_begin(void);
72static void wps_print_process_outputs_end(void);
73static void wps_print_bounding_box_data(void);
74static void wps_print_ident_title_abstract(const char *, const char *, const char *);
75static void wps_print_complex_input(int , int , const char *, const char *, const char *, int , int );
76static void wps_print_complex_output(const char *, const char *, const char *, int );
77static void wps_print_comlpex_input_output(int , int , int , const char *, const char *, const char *, int , int );
78static void wps_print_literal_input_output(int , int , int , const char *,
79 const char *, const char *, const char *, int ,
80 const char **, int , const char *, int );
81
82static void print_escaped_for_xml(FILE * fp, const char *str)
83{
84 for (; *str; str++) {
85 switch (*str) {
86 case '&':
87 fputs("&amp;", fp);
88 break;
89 case '<':
90 fputs("&lt;", fp);
91 break;
92 case '>':
93 fputs("&gt;", fp);
94 break;
95 default:
96 fputc(*str, fp);
97 }
98 }
99}
100
101/*!
102 * \brief Print the WPS 1.0.0 process description XML document to stdout
103 *
104 * A module started with the parameter "--wps-process-description"
105 * will write a process description XML document to stdout and exit.
106 *
107 * Currently only raster and vector modules are supported, but the
108 * generation works with any module (more or less meaningful).
109 * Most of the input options are caught:
110 * * single and multiple raster and vector maps
111 * * single and multiple string, float and integer data with default
112 * values and value options (range is missing)
113 * Flags are supported as boolean values.
114 *
115 * The mime types for vector maps are GML, KML, dgn, shape and zipped shape.
116 *
117 * The mime types for raster maps are tiff, geotiff, hfa, netcdf, gif, jpeg and png.
118 *
119 * Mime types for space time datasets are tar archives with gz, bzip or without compression
120 *
121 * The mime types are reflecting the capabilities of grass and gdal and may be extended.
122 *
123 * BoundignBox support is currently not available for inputs and outputs.
124 * Literal data output (string, float or integer) is currently not supported.
125 *
126 * In case no output parameter was set (new raster of vector map) the stdout output
127 * is noticed as output parameter of mime type text/plain.
128 *
129 * Multiple vector or raster map outputs marked as one option are not supported (wps 1.0.0 specification
130 * does not allow multiple outputs with only one identifier).
131 * Multiple outputs must be wrapped via a python script or created as group.
132 *
133 * In future the following mimetypes may be supported
134 * mime type: application/grass-vector-ascii -> a text file generated with v.out.asci
135 * Example.: urn:file:///path/name
136 * mime type: application/grass-vector-binary -> the binary vectors must be addressed with a non standard urn:
137 * Example: urn:grass:vector:location/mapset/name
138 * */
139
141{
142 struct Option *opt;
143 struct Flag *flag;
144 char *type;
145 char *s, *top;
146 const char *value = NULL;
147 int i;
148 const char *encoding;
149 int new_prompt = 0;
150 int store = 1;
151 int status = 1;
152 const char *identifier = NULL;
153 const char *title = NULL;
154 const char *abstract = NULL;
155 const char **keywords = NULL;
156 int data_type, is_input, is_output;
157 int num_raster_inputs = 0, num_raster_outputs = 0;
158 int num_vector_inputs = 0, num_vector_outputs = 0;
159 int num_strds_inputs = 0, num_strds_outputs = 0;
160 int num_stvds_inputs = 0, num_stvds_outputs = 0;
161 int min = 0, max = 0;
162 int num_keywords = 0;
163 int found_output = 0;
164 int is_tuple; /* Checks the key_descr for comma separated values */
165 int num_tuples; /* Counts the "," in key_descr */
166
167 new_prompt = G__uses_new_gisprompt();
168
169 /* gettext converts strings to encoding returned by nl_langinfo(CODESET) */
170
171#if defined(HAVE_LANGINFO_H)
172 encoding = nl_langinfo(CODESET);
173 if (!encoding || strlen(encoding) == 0) {
174 encoding = "UTF-8";
175 }
176#elif defined(__MINGW32__) && defined(USE_NLS)
177 encoding = locale_charset();
178 if (!encoding || strlen(encoding) == 0) {
179 encoding = "UTF-8";
180 }
181#else
182 encoding = "UTF-8";
183#endif
184
185 if (!st->pgm_name)
186 st->pgm_name = G_program_name();
187 if (!st->pgm_name)
188 st->pgm_name = "??";
189
190 /* the identifier of the process is the module name */
191 identifier = st->pgm_name;
192
193 if (st->module_info.description) {
194 title = st->module_info.description;
195 abstract = st->module_info.description;
196 }
197
198 if (st->module_info.keywords) {
199 keywords = st->module_info.keywords;
200 num_keywords = st->n_keys;
201 }
202
203 wps_print_process_descriptions_begin();
204 /* store and status are supported as default. The WPS server should change this if necessary */
205 wps_print_process_description_begin(store, status, identifier, title, abstract, keywords, num_keywords);
206 wps_print_data_inputs_begin();
207
208 /* Print the bounding box element with all the coordinate reference systems, which are supported by grass*/
209 /* Currently Disabled! A list of all proj4 supported EPSG coordinate reference systems must be implemented*/
210 if(1 == 0)
211 wps_print_bounding_box_data();
212
213 /* We parse only the inputs at the beginning */
214 if (st->n_opts) {
215 opt = &st->first_option;
216 while (opt != NULL) {
217
218 identifier = NULL;
219 title = NULL;
220 abstract = NULL;
221 keywords = NULL;
222 num_keywords = 0;
223 value = NULL;
224 is_input = 1;
225 is_output = 0;
226 is_tuple = 0;
227 num_tuples = 0;
228 data_type = TYPE_OTHER;
229
230 /* Check the gisprompt */
231 if (opt->gisprompt) {
232 const char *atts[] = { "age", "element", "prompt", NULL };
233 top = G_calloc(strlen(opt->gisprompt) + 1, 1);
234 strcpy(top, opt->gisprompt);
235 s = strtok(top, ",");
236 for (i = 0; s != NULL && atts[i] != NULL; i++) {
237
238 char *token = G_store(s);
239
240 /* we print only input parameter, sort out the output parameter */
241 if(strcmp(token, "new") == 0) {
242 is_input = 0;
243 is_output = 1;
244 }
245 if(strcmp(token, "raster") == 0)
246 {
247 data_type = TYPE_RASTER;
248 /* Count the raster inputs and outputs for default option creation */
249 if(is_input == 1)
250 num_raster_inputs++;
251 if(is_output == 1)
252 num_raster_outputs++;
253 }
254 if(strcmp(token, "vector") == 0)
255 {
256 data_type = TYPE_VECTOR;
257 if(is_input == 1)
258 num_vector_inputs++;
259 if(is_output == 1)
260 num_vector_outputs++;
261 }
262 /* Modules may have different types of space time datasets as inputs */
263 if(strcmp(token, "stds") == 0)
264 {
265 data_type = TYPE_STDS;
266 }
267 if(strcmp(token, "strds") == 0)
268 {
269 data_type = TYPE_STRDS;
270 if(is_input == 1)
271 num_strds_inputs++;
272 if(is_output == 1)
273 num_strds_outputs++;
274 }
275 if(strcmp(token, "stvds") == 0)
276 {
277 data_type = TYPE_STVDS;
278 if(is_input == 1)
279 num_stvds_inputs++;
280 if(is_output == 1)
281 num_stvds_outputs++;
282 }
283 if(strcmp(token, "file") == 0)
284 {
285 data_type = TYPE_PLAIN_TEXT;
286 }
287 s = strtok(NULL, ",");
288 G_free(token);
289 }
290 G_free(top);
291 }
292
293 /* Check the key description */
294 if (opt->key_desc) {
295 top = G_calloc(strlen(opt->key_desc) + 1, 1);
296 strcpy(top, opt->key_desc);
297 s = strtok(top, ",");
298 /* Count comma's */
299 for (i = 0; s != NULL; i++) {
300 num_tuples++;
301 s = strtok(NULL, ",");
302 }
303 if(num_tuples > 1)
304 is_tuple = 1;
305
306 G_free(top);
307 }
308 /* We have an input option */
309 if(is_input == 1)
310 {
311 switch (opt->type) {
312 case TYPE_INTEGER:
313 type = "integer";
314 break;
315 case TYPE_DOUBLE:
316 type = "float";
317 break;
318 case TYPE_STRING:
319 type = "string";
320 break;
321 default:
322 type = "string";
323 break;
324 }
325
326 identifier = opt->key;
327
328 if(opt->required == YES) {
329 if(is_tuple)
330 min = num_tuples;
331 else
332 min = 1;
333 } else {
334 min = 0;
335 }
336
337 if(opt->multiple == YES) {
338 max = 1024;
339 } else {
340 if(is_tuple)
341 max = num_tuples;
342 else
343 max = 1;
344 }
345
346 if(opt->label) {
347 title = opt->label;
348 }
349 if (opt->description) {
350 if(!opt->label)
351 title = opt->description;
352 else
353 abstract = opt->description;
354 }
355 if (opt->def) {
356 value = opt->def;
357 }
358 if (opt->options) {
359 /* TODO:
360 * add something like
361 * <range min="xxx" max="xxx"/>
362 * to <values> */
363 i = 0;
364 while (opt->opts[i]) {
365 i++;
366 }
367 keywords = opt->opts;
368 num_keywords = i;
369 }
370 if(data_type == TYPE_RASTER || data_type == TYPE_VECTOR ||
371 data_type == TYPE_STRDS || data_type == TYPE_STVDS ||
372 data_type == TYPE_STDS || data_type == TYPE_PLAIN_TEXT)
373 {
374 /* 2048 is the maximum size of the map in mega bytes */
375 wps_print_complex_input(min, max, identifier, title, abstract, 2048, data_type);
376 }
377 else
378 {
379 /* The keyword array is missused for options, type means the type of the value (integer, float ... )*/
380 wps_print_literal_input_output(WPS_INPUT, min, max, identifier, title,
381 abstract, type, 0, keywords, num_keywords, value, TYPE_OTHER);
382 }
383 }
384 opt = opt->next_opt;
385 }
386 }
387
388 /* Flags are always input options and can be false or true (boolean) */
389 if (st->n_flags) {
390 flag = &st->first_flag;
391 while (flag != NULL) {
392
393 /* The identifier is the flag "-x" */
394 char* ident = (char*)G_calloc(3, sizeof(char));
395 ident[0] = '-';
396 ident[1] = flag->key;
397 ident[2] = '\0';
398 title = NULL;
399 abstract = NULL;
400
401 if (flag->description) {
402 title = flag->description;
403 abstract = flag->description;
404 }
405 const char *val[] = {"true","false"};
406 wps_print_literal_input_output(WPS_INPUT, 0, 1, ident, title, NULL, "boolean", 0, val, 2, "false", TYPE_OTHER);
407 flag = flag->next_flag;
408 }
409 }
410
411 /* We have two default options, which define the resolution of the created mapset */
412 if(num_raster_inputs > 0 || num_raster_outputs > 0 || num_strds_inputs > 0 || num_strds_outputs > 0) {
413 wps_print_literal_input_output(WPS_INPUT, 0, 1, "grass_resolution_ns", "Resolution of the mapset in north-south direction in meters or degrees",
414 "This parameter defines the north-south resolution of the mapset in meter or degrees, which should be used to process the input and output raster data. To enable this setting, you need to specify north-south and east-west resolution.",
415 "float", 1, NULL, 0, NULL, TYPE_OTHER);
416 wps_print_literal_input_output(WPS_INPUT, 0, 1, "grass_resolution_ew", "Resolution of the mapset in east-west direction in meters or degrees",
417 "This parameter defines the east-west resolution of the mapset in meters or degrees, which should be used to process the input and output raster data. To enable this setting, you need to specify north-south and east-west resolution.",
418 "float", 1, NULL, 0, NULL, TYPE_OTHER);
419 }
420 /* In case multi band raster maps should be imported, the band number must be provided */
421 if(num_raster_inputs > 0)
422 wps_print_literal_input_output(WPS_INPUT, 0, 1, "grass_band_number", "Band to select for processing (default is all bands)",
423 "This parameter defines band number of the input raster files which should be processed. As default all bands are processed and used as single and multiple inputs for raster modules.",
424 "integer", 0, NULL, 0, NULL, TYPE_OTHER);
425
426 /* End of inputs */
427 wps_print_data_inputs_end();
428 /* Start of the outputs */
429 wps_print_process_outputs_begin();
430
431 found_output = 0;
432
433 /*parse the output. only raster maps, vector maps, space time raster and vector datasets plus stdout are supported */
434 if (st->n_opts) {
435 opt = &st->first_option;
436 while (opt != NULL) {
437
438 identifier = NULL;
439 title = NULL;
440 abstract = NULL;
441 value = NULL;
442 is_output = 0;
443 data_type = TYPE_OTHER;
444
445 if (opt->gisprompt) {
446 const char *atts[] = { "age", "element", "prompt", NULL };
447 top = G_calloc(strlen(opt->gisprompt) + 1, 1);
448 strcpy(top, opt->gisprompt);
449 s = strtok(top, ",");
450 for (i = 0; s != NULL && atts[i] != NULL; i++) {
451
452 char *token = G_store(s);
453
454 /* we print only the output parameter */
455 if(strcmp(token, "new") == 0)
456 is_output = 1;
457 if(strcmp(token, "raster") == 0)
458 {
459 data_type = TYPE_RASTER;
460 }
461 if(strcmp(token, "vector") == 0)
462 {
463 data_type = TYPE_VECTOR;
464 }
465 if(strcmp(token, "stds") == 0)
466 {
467 data_type = TYPE_STDS;
468 }
469 if(strcmp(token, "strds") == 0)
470 {
471 data_type = TYPE_STRDS;
472 }
473 if(strcmp(token, "stvds") == 0)
474 {
475 data_type = TYPE_STVDS;
476 }
477 if(strcmp(token, "file") == 0)
478 {
479 data_type = TYPE_PLAIN_TEXT;
480 }
481 s = strtok(NULL, ",");
482 G_free(token);
483 }
484 G_free(top);
485 }
486 /* Only single module output is supported!! */
487 if(is_output == 1)
488 {
489 if(opt->multiple == YES)
490 G_warning(_("Multiple outputs are not supported by WPS 1.0.0"));
491 identifier = opt->key;
492
493 if(opt->label) {
494 title = opt->label;
495 }
496 if (opt->description) {
497 if(!opt->label)
498 title = opt->description;
499 else
500 abstract = opt->description;
501 }
502
503 if(data_type == TYPE_RASTER || data_type == TYPE_VECTOR ||
504 data_type == TYPE_STRDS || data_type == TYPE_STVDS ||
505 data_type == TYPE_STDS || data_type == TYPE_PLAIN_TEXT) {
506 wps_print_complex_output(identifier, title, abstract, data_type);
507 found_output = 1;
508 }
509 }
510 opt = opt->next_opt;
511 }
512 /* we assume the computatuon output on stdout, if no raster/vector output was found*/
513 if(found_output == 0)
514 wps_print_complex_output("stdout", "Module output on stdout", "The output of the module written to stdout", TYPE_PLAIN_TEXT);
515 }
516
517 wps_print_process_outputs_end();
518 wps_print_process_description_end();
519 wps_print_process_descriptions_end();
520}
521
522
523/**************************************************************************
524 *
525 * The remaining routines are all local (static) routines used to support
526 * the the creation of the WPS process_description document.
527 *
528 **************************************************************************/
529
530static void wps_print_process_descriptions_begin(void)
531{
532 fprintf(stdout, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
533 fprintf(stdout, "<wps:ProcessDescriptions xmlns:wps=\"http://www.opengis.net/wps/1.0.0\"\n");
534 fprintf(stdout, "xmlns:ows=\"http://www.opengis.net/ows/1.1\"\n");
535 fprintf(stdout, "xmlns:xlink=\"http://www.w3.org/1999/xlink\"\n");
536 fprintf(stdout, "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n");
537 fprintf(stdout, "xsi:schemaLocation=\"http://www.opengis.net/wps/1.0.0\n http://schemas.opengis.net/wps/1.0.0/wpsDescribeProcess_response.xsd\"\n service=\"WPS\" version=\"1.0.0\" xml:lang=\"en-US\"> \n");
538}
539
540/* ************************************************************************** */
541
542static void wps_print_process_descriptions_end(void)
543{
544 fprintf(stdout,"</wps:ProcessDescriptions>\n");
545}
546
547/* ************************************************************************** */
548
549static void wps_print_process_description_begin(int store, int status, const char *identifier,
550 const char *title, const char *abstract,
551 const char **keywords, int num_keywords)
552{
553 int i;
554
555 fprintf(stdout,"\t<ProcessDescription wps:processVersion=\"1\" storeSupported=\"%s\" statusSupported=\"%s\">\n", (store?"true":"false"), (status?"true":"false"));
556 if(identifier)
557 {
558 fprintf(stdout,"\t\t<ows:Identifier>");
559 print_escaped_for_xml(stdout, identifier);
560 fprintf(stdout,"</ows:Identifier>\n");
561 } else {
562 G_fatal_error("Identifier not defined");
563 }
564
565 if(title)
566 {
567 fprintf(stdout,"\t\t<ows:Title>");
568 print_escaped_for_xml(stdout, title);
569 fprintf(stdout, "</ows:Title>\n");
570 } else {
571 G_warning("Title not defined!");
572 fprintf(stdout,"\t\t<ows:Title>");
573 print_escaped_for_xml(stdout, "No title available");
574 fprintf(stdout, "</ows:Title>\n");
575 }
576
577
578 if(abstract)
579 {
580 fprintf(stdout,"\t\t<ows:Abstract>");
581 fprintf(stdout, "https://grass.osgeo.org/grass-devel/manuals/%s.html", identifier);
582 fprintf(stdout, "</ows:Abstract>\n");
583 }
584
585 for(i = 0; i < num_keywords; i++)
586 {
587 fprintf(stdout,"\t\t<ows:Metadata xlink:title=\"");
588 print_escaped_for_xml(stdout, keywords[i]);
589 fprintf(stdout, "\" />\n");
590 }
591}
592
593/* ************************************************************************** */
594
595static void wps_print_process_description_end(void)
596{
597 fprintf(stdout,"\t</ProcessDescription>\n");
598}
599
600/* ************************************************************************** */
601
602static void wps_print_data_inputs_begin(void)
603{
604 fprintf(stdout,"\t\t<DataInputs>\n");
605}
606
607/* ************************************************************************** */
608
609static void wps_print_data_inputs_end(void)
610{
611 fprintf(stdout,"\t\t</DataInputs>\n");
612}
613
614/* ************************************************************************** */
615
616static void wps_print_process_outputs_begin(void)
617{
618 fprintf(stdout,"\t\t<ProcessOutputs>\n");
619}
620
621/* ************************************************************************** */
622
623static void wps_print_process_outputs_end(void)
624{
625 fprintf(stdout,"\t\t</ProcessOutputs>\n");
626}
627
628/* ************************************************************************** */
629
630static void wps_print_complex_input(int min, int max, const char *identifier, const char *title, const char *abstract, int megs, int type)
631{
632 wps_print_comlpex_input_output(WPS_INPUT, min, max, identifier, title, abstract, megs, type);
633}
634
635/* ************************************************************************** */
636
637static void wps_print_complex_output(const char *identifier, const char *title, const char *abstract, int type)
638{
639 wps_print_comlpex_input_output(WPS_OUTPUT, 0, 0, identifier, title, abstract, 0, type);
640}
641
642/* ************************************************************************** */
643
644static void wps_print_comlpex_input_output(int inout_type, int min, int max, const char *identifier, const char *title, const char *abstract, int megs, int type)
645{
646 if(inout_type == WPS_INPUT)
647 fprintf(stdout,"\t\t\t<Input minOccurs=\"%i\" maxOccurs=\"%i\">\n", min, max);
648 else if(inout_type == WPS_OUTPUT)
649 fprintf(stdout,"\t\t\t<Output>\n");
650
651 wps_print_ident_title_abstract(identifier, title, abstract);
652
653 if(inout_type == WPS_INPUT)
654 fprintf(stdout,"\t\t\t\t<ComplexData maximumMegabytes=\"%i\">\n", megs);
655 else if(inout_type == WPS_OUTPUT)
656 fprintf(stdout,"\t\t\t\t<ComplexOutput>\n");
657
658 fprintf(stdout,"\t\t\t\t\t<Default>\n");
659 if(type == TYPE_RASTER)
660 {
661 wps_print_mimetype_raster_tiff();
662 }
663 else if(type == TYPE_VECTOR)
664 {
665 wps_print_mimetype_vector_gml311();
666 }
667 else if(type == TYPE_STDS)
668 {
669 /* A space time raster dataset is the default an any modules with multiple dataset options */
670 wps_print_mimetype_space_time_raster_datasets_tar_gz();
671 }
672 else if(type == TYPE_STRDS)
673 {
674 wps_print_mimetype_space_time_raster_datasets_tar_gz();
675 }
676 else if(type == TYPE_STVDS)
677 {
678 wps_print_mimetype_space_time_vector_datasets_tar_gz();
679 }
680 else if(type == TYPE_PLAIN_TEXT)
681 {
682 wps_print_mimetype_text_plain();
683 }
684 fprintf(stdout,"\t\t\t\t\t</Default>\n");
685 fprintf(stdout,"\t\t\t\t\t<Supported>\n");
686 if(type == TYPE_RASTER)
687 {
688 /*The supported types for input and output are different*/
689 if(inout_type == WPS_INPUT) {
690 wps_print_mimetype_raster_tiff();
691 wps_print_mimetype_raster_tiff_other();
692 wps_print_mimetype_raster_png();
693 wps_print_mimetype_raster_gif();
694 wps_print_mimetype_raster_jpeg();
695 wps_print_mimetype_raster_hfa();
696 wps_print_mimetype_raster_netCDF();
697 wps_print_mimetype_raster_netCDF_other();
698 } else {
699 wps_print_mimetype_raster_tiff();
700 wps_print_mimetype_raster_tiff_other();
701 wps_print_mimetype_raster_hfa();
702 wps_print_mimetype_raster_netCDF();
703 wps_print_mimetype_raster_netCDF_other();
704 }
705 }
706 else if(type == TYPE_VECTOR)
707 {
708 if(inout_type == WPS_INPUT) {
709 wps_print_mimetype_vector_gml311();
710 wps_print_mimetype_vector_gml311_appl();
711 wps_print_mimetype_vector_gml212();
712 wps_print_mimetype_vector_gml212_appl();
713 wps_print_mimetype_vector_kml22();
714 wps_print_mimetype_vector_dgn();
715 wps_print_mimetype_vector_shape();
716 wps_print_mimetype_vector_zipped_shape();
717 } else {
718 wps_print_mimetype_vector_gml311();
719 wps_print_mimetype_vector_gml311_appl();
720 wps_print_mimetype_vector_gml212();
721 wps_print_mimetype_vector_gml212_appl();
722 wps_print_mimetype_vector_kml22();
723 }
724 }
725 else if(type == TYPE_STDS)
726 {
727 wps_print_mimetype_space_time_datasets();
728 }
729 else if(type == TYPE_STRDS)
730 {
731 wps_print_mimetype_space_time_raster_datasets();
732 }
733 else if(type == TYPE_STVDS)
734 {
735 wps_print_mimetype_space_time_vector_datasets();
736 }
737 else if(type == TYPE_PLAIN_TEXT)
738 {
739 wps_print_mimetype_text_plain();
740 }
741 fprintf(stdout,"\t\t\t\t\t</Supported>\n");
742
743 if(inout_type == WPS_INPUT)
744 fprintf(stdout,"\t\t\t\t</ComplexData>\n");
745 else if(inout_type == WPS_OUTPUT)
746 fprintf(stdout,"\t\t\t\t</ComplexOutput>\n");
747
748 if(inout_type == WPS_INPUT)
749 fprintf(stdout,"\t\t\t</Input>\n");
750 else if(inout_type == WPS_OUTPUT)
751 fprintf(stdout,"\t\t\t</Output>\n");
752}
753
754/* ************************************************************************** */
755
756static void wps_print_ident_title_abstract(const char *identifier, const char *title, const char *abstract)
757{
758 if(identifier)
759 {
760 fprintf(stdout,"\t\t\t\t<ows:Identifier>");
761 print_escaped_for_xml(stdout, identifier);
762 fprintf(stdout,"</ows:Identifier>\n");
763 } else {
764 G_fatal_error("Identifier not defined");
765 }
766
767 if(title)
768 {
769 fprintf(stdout,"\t\t\t\t<ows:Title>");
770 print_escaped_for_xml(stdout, title);
771 fprintf(stdout, "</ows:Title>\n");
772 } else {
773 G_warning("Title not defined!");
774 fprintf(stdout,"\t\t\t\t<ows:Title>");
775 print_escaped_for_xml(stdout, "No title available");
776 fprintf(stdout, "</ows:Title>\n");
777 }
778
779 if(abstract)
780 {
781 fprintf(stdout,"\t\t\t\t<ows:Abstract>");
782 print_escaped_for_xml(stdout, abstract);
783 fprintf(stdout, "</ows:Abstract>\n");
784 }
785}
786
787/* ************************************************************************** */
788
789static void wps_print_literal_input_output(int inout_type, int min, int max, const char *identifier,
790 const char *title, const char *abstract, const char *datatype, int unitofmesure,
791 const char **choices, int num_choices, const char *default_value, int type)
792{
793 int i;
794 char range[2][24];
795 char *str;
796
797 if(inout_type == WPS_INPUT)
798 fprintf(stdout,"\t\t\t<Input minOccurs=\"%i\" maxOccurs=\"%i\">\n", min, max);
799 else if(inout_type == WPS_OUTPUT)
800 fprintf(stdout,"\t\t\t<Output>\n");
801
802 wps_print_ident_title_abstract(identifier, title, abstract);
803
804 fprintf(stdout,"\t\t\t\t<LiteralData>\n");
805
806 if(datatype)
807 fprintf(stdout,"\t\t\t\t\t<ows:DataType ows:reference=\"xs:%s\">%s</ows:DataType>\n", datatype, datatype);
808
809 if(unitofmesure)
810 {
811 fprintf(stdout,"\t\t\t\t\t<UOMs>\n");
812 fprintf(stdout,"\t\t\t\t\t\t<Default>\n");
813 fprintf(stdout,"\t\t\t\t\t\t\t<ows:UOM>meters</ows:UOM>\n");
814 fprintf(stdout,"\t\t\t\t\t\t</Default>\n");
815 fprintf(stdout,"\t\t\t\t\t\t<Supported>\n");
816 fprintf(stdout,"\t\t\t\t\t\t\t<ows:UOM>meters</ows:UOM>\n");
817 fprintf(stdout,"\t\t\t\t\t\t\t<ows:UOM>degrees</ows:UOM>\n");
818 fprintf(stdout,"\t\t\t\t\t\t</Supported>\n");
819 fprintf(stdout,"\t\t\t\t\t</UOMs>\n");
820 }
821 if(num_choices == 0 || choices == NULL)
822 fprintf(stdout,"\t\t\t\t\t<ows:AnyValue/>\n");
823 else
824 {
825 /* Check for range values */
826 if(strcmp(datatype, "integer") == 0 || strcmp(datatype, "float") == 0) {
827 str = strtok((char*)choices[0], "-");
828 if(str != NULL) {
829 G_snprintf(range[0], 24, "%s", str);
830 str = strtok(NULL, "-");
831 if(str != NULL) {
832 G_snprintf(range[1], 24, "%s", str);
833 type = TYPE_RANGE;
834 }
835 }
836 }
837
838 fprintf(stdout,"\t\t\t\t\t<ows:AllowedValues>\n");
839 if(type == TYPE_RANGE)
840 {
841 fprintf(stdout,"\t\t\t\t\t\t<ows:Range ows:rangeClosure=\"closed\">\n");
842 fprintf(stdout,"\t\t\t\t\t\t\t<ows:MinimumValue>%s</ows:MinimumValue>\n", range[0]);
843 fprintf(stdout,"\t\t\t\t\t\t\t<ows:MaximumValue>%s</ows:MaximumValue>\n", range[1]);
844 fprintf(stdout,"\t\t\t\t\t\t</ows:Range>\n");
845 }
846 else
847 {
848 for(i = 0; i < num_choices; i++)
849 {
850 fprintf(stdout,"\t\t\t\t\t\t<ows:Value>");
851 print_escaped_for_xml(stdout, choices[i]);
852 fprintf(stdout,"</ows:Value>\n");
853 }
854 }
855 fprintf(stdout,"\t\t\t\t\t</ows:AllowedValues>\n");
856 }
857
858 if(default_value)
859 {
860 fprintf(stdout,"\t\t\t\t\t<DefaultValue>");
861 print_escaped_for_xml(stdout, default_value);
862 fprintf(stdout,"</DefaultValue>\n");
863 }
864 fprintf(stdout,"\t\t\t\t</LiteralData>\n");
865
866
867 if(inout_type == WPS_INPUT)
868 fprintf(stdout,"\t\t\t</Input>\n");
869 else if(inout_type == WPS_OUTPUT)
870 fprintf(stdout,"\t\t\t</Output>\n");
871}
872
873/* ************************************************************************** */
874
875static void wps_print_mimetype_text_plain(void)
876{
877 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
878 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>text/plain</MimeType>\n");
879 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
880}
881/* ************************************************************************** */
882
883static void wps_print_mimetype_raster_tiff(void)
884{
885 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
886 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>image/tiff</MimeType>\n");
887 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
888}
889
890/* ************************************************************************** */
891
892static void wps_print_mimetype_raster_png(void)
893{
894 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
895 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>image/png</MimeType>\n");
896 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
897}
898
899/* *** Native GRASS raster format urn:grass:raster:location/mapset/raster *** */
900
901static void wps_print_mimetype_raster_grass_binary(void)
902{
903 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
904 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/grass-raster-binary</MimeType>\n");
905 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
906}
907
908/* *** GRASS raster maps exported via r.out.ascii ************************** */
909
910static void wps_print_mimetype_raster_grass_ascii(void)
911{
912 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
913 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/grass-raster-ascii</MimeType>\n");
914 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
915}
916
917/* ************************************************************************** */
918
919static void wps_print_mimetype_vector_gml311_appl(void)
920{
921 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
922 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/xml</MimeType>\n");
923 fprintf(stdout,"\t\t\t\t\t\t\t<Encoding>UTF-8</Encoding>\n");
924 fprintf(stdout,"\t\t\t\t\t\t\t<Schema>http://schemas.opengis.net/gml/3.1.1/base/gml.xsd</Schema>\n");
925 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
926}
927
928/* ************************************************************************** */
929
930static void wps_print_mimetype_vector_gml212_appl(void)
931{
932 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
933 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/xml</MimeType>\n");
934 fprintf(stdout,"\t\t\t\t\t\t\t<Encoding>UTF-8</Encoding>\n");
935 fprintf(stdout,"\t\t\t\t\t\t\t<Schema>http://schemas.opengis.net/gml/2.1.2/feature.xsd</Schema>\n");
936 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
937}
938
939
940/* ************************************************************************** */
941
942static void wps_print_mimetype_vector_gml311(void)
943{
944 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
945 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>text/xml</MimeType>\n");
946 fprintf(stdout,"\t\t\t\t\t\t\t<Encoding>UTF-8</Encoding>\n");
947 fprintf(stdout,"\t\t\t\t\t\t\t<Schema>http://schemas.opengis.net/gml/3.1.1/base/gml.xsd</Schema>\n");
948 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
949}
950
951/* ************************************************************************** */
952
953static void wps_print_mimetype_vector_gml212(void)
954{
955 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
956 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>text/xml</MimeType>\n");
957 fprintf(stdout,"\t\t\t\t\t\t\t<Encoding>UTF-8</Encoding>\n");
958 fprintf(stdout,"\t\t\t\t\t\t\t<Schema>http://schemas.opengis.net/gml/2.1.2/feature.xsd</Schema>\n");
959 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
960}
961
962/* *** GRASS vector format exported via v.out.ascii ************************** */
963
964static void wps_print_mimetype_vector_grass_ascii(void)
965{
966 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
967 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/grass-vector-ascii</MimeType>\n");
968 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
969}
970
971/* *** Native GRASS vector format urn:grass:vector:location/mapset/vector *** */
972
973static void wps_print_mimetype_vector_grass_binary(void)
974{
975 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
976 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/grass-vector-binary</MimeType>\n");
977 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
978}
979
980/* *** Space time dataset format using tar, tar.gz and tar.bz2 methods for packaging */
981
982static void wps_print_mimetype_space_time_datasets(void)
983{
984 wps_print_mimetype_space_time_raster_datasets();
985 wps_print_mimetype_space_time_vector_datasets();
986}
987
988/* *** Space time raster dataset format using tar, tar.gz and tar.bz2 methods for packaging */
989
990static void wps_print_mimetype_space_time_raster_datasets(void)
991{
992 wps_print_mimetype_space_time_raster_datasets_tar();
993 wps_print_mimetype_space_time_raster_datasets_tar_gz();
994 wps_print_mimetype_space_time_raster_datasets_tar_bz2();
995}
996
997static void wps_print_mimetype_space_time_raster_datasets_tar(void)
998{
999 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1000 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-grass-strds-tar</MimeType>\n");
1001 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1002}
1003
1004static void wps_print_mimetype_space_time_raster_datasets_tar_gz(void)
1005{
1006 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1007 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-grass-strds-tar-gz</MimeType>\n");
1008 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1009}
1010
1011static void wps_print_mimetype_space_time_raster_datasets_tar_bz2(void)
1012{
1013 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1014 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-grass-strds-tar-bzip</MimeType>\n");
1015 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1016}
1017
1018
1019/* *** Space time vector dataset format using tar, tar.gz and tar.bz2 methods for packaging */
1020
1021static void wps_print_mimetype_space_time_vector_datasets(void)
1022{
1023 wps_print_mimetype_space_time_vector_datasets_tar();
1024 wps_print_mimetype_space_time_vector_datasets_tar_gz();
1025 wps_print_mimetype_space_time_vector_datasets_tar_bz2();
1026}
1027
1028static void wps_print_mimetype_space_time_vector_datasets_tar(void)
1029{
1030 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1031 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-grass-stvds-tar</MimeType>\n");
1032 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1033}
1034
1035static void wps_print_mimetype_space_time_vector_datasets_tar_gz(void)
1036{
1037 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1038 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-grass-stvds-tar-gz</MimeType>\n");
1039 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1040}
1041
1042static void wps_print_mimetype_space_time_vector_datasets_tar_bz2(void)
1043{
1044 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1045 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-grass-stvds-tar-bzip</MimeType>\n");
1046 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1047}
1048
1049/* ************************************************************************** */
1050static void wps_print_mimetype_raster_gif(void)
1051{
1052 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1053 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>image/gif</MimeType>\n");
1054 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1055}
1056
1057/* ************************************************************************** */
1058static void wps_print_mimetype_raster_jpeg(void)
1059{
1060 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1061 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>image/jpeg</MimeType>\n");
1062 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1063}
1064
1065/* ************************************************************************** */
1066static void wps_print_mimetype_raster_hfa(void)
1067{
1068 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1069 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-erdas-hfa</MimeType>\n");
1070 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1071}
1072/* ************************************************************************** */
1073
1074static void wps_print_mimetype_raster_tiff_other(void)
1075{
1076 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1077 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>image/geotiff</MimeType>\n");
1078 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1079
1080 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1081 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/geotiff</MimeType>\n");
1082 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1083
1084 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1085 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-geotiff</MimeType>\n");
1086 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1087}
1088
1089/* ************************************************************************** */
1090static void wps_print_mimetype_raster_netCDF(void)
1091{
1092 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1093 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/netcdf</MimeType>\n");
1094 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1095}
1096
1097/* ************************************************************************** */
1098static void wps_print_mimetype_raster_netCDF_other(void)
1099{
1100 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1101 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-netcdf</MimeType>\n");
1102 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1103}
1104
1105/* ************************************************************************** */
1106static void wps_print_mimetype_vector_kml22(void)
1107{
1108 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1109 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>text/xml</MimeType>\n");
1110 fprintf(stdout,"\t\t\t\t\t\t\t<Encoding>UTF-8</Encoding>\n");
1111 fprintf(stdout,"\t\t\t\t\t\t\t<Schema>http://schemas.opengis.net/kml/2.2.0/ogckml22.xsd</Schema>\n");
1112 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1113}
1114
1115/* ************************************************************************** */
1116static void wps_print_mimetype_vector_dgn(void)
1117{
1118 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1119 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/dgn</MimeType>\n");
1120 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1121}
1122
1123/* ************************************************************************** */
1124static void wps_print_mimetype_vector_shape(void)
1125{
1126 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1127 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/shp</MimeType>\n");
1128 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1129}
1130
1131/* ************************************************************************** */
1132static void wps_print_mimetype_vector_zipped_shape(void)
1133{
1134 fprintf(stdout,"\t\t\t\t\t\t<Format>\n");
1135 fprintf(stdout,"\t\t\t\t\t\t\t<MimeType>application/x-zipped-shp</MimeType>\n");
1136 fprintf(stdout,"\t\t\t\t\t\t</Format>\n");
1137}
1138
1139/* Bounding box data input. Do not use! Under construction. A list of coordinate reference systems must be created.*/
1140
1141static void wps_print_bounding_box_data(void)
1142{
1143 int i;
1144
1145 fprintf(stdout,"\t\t\t<Input minOccurs=\"0\" maxOccurs=\"1\">\n");
1146 wps_print_ident_title_abstract("BoundingBox", "Bounding box to process data",
1147 "The bounding box is uesed to create the reference coordinate system in grass, as well as the lower left and upper right corner of the processing area.");
1148 fprintf(stdout,"\t\t\t\t<BoundingBoxData>\n");
1149 /* A meaningful default boundingbox should be chosen*/
1150 fprintf(stdout,"\t\t\t\t\t<Default>\n");
1151 fprintf(stdout,"\t\t\t\t\t\t<CRS>urn:ogc:def:crs,crs:EPSG:6.3:32760</CRS>\n");
1152 fprintf(stdout,"\t\t\t\t\t</Default>\n");
1153 /* A list of all proj4 supported EPSG coordinate systems should be created */
1154 fprintf(stdout,"\t\t\t\t\t<Supported>\n");
1155 for(i = 0; i < 1; i++)
1156 fprintf(stdout,"\t\t\t\t\t\t<CRS>urn:ogc:def:crs,crs:EPSG:6.3:32760</CRS>\n");
1157 fprintf(stdout,"\t\t\t\t\t</Supported>\n");
1158 fprintf(stdout,"\t\t\t\t</BoundingBoxData>\n");
1159 fprintf(stdout,"\t\t\t</Input>\n");
1160}
1161
void G_free(void *buf)
Free allocated memory.
Definition: alloc.c:149
#define NULL
Definition: ccmath.h:32
void G_fatal_error(const char *msg,...)
Print a fatal error message to stderr.
Definition: gis/error.c:160
void G_warning(const char *msg,...)
Print a warning message to stderr.
Definition: gis/error.c:204
int G__uses_new_gisprompt(void)
Definition: parser.c:874
struct state * st
Definition: parser.c:104
#define TYPE_RANGE
Definition: parser_wps.c:26
#define TYPE_STDS
Definition: parser_wps.c:28
#define TYPE_STRDS
Definition: parser_wps.c:29
#define TYPE_STVDS
Definition: parser_wps.c:30
#define WPS_INPUT
Definition: parser_wps.c:31
#define TYPE_VECTOR
Definition: parser_wps.c:24
#define TYPE_RASTER
Definition: parser_wps.c:23
void G__wps_print_process_description(void)
Print the WPS 1.0.0 process description XML document to stdout.
Definition: parser_wps.c:140
#define TYPE_PLAIN_TEXT
Definition: parser_wps.c:25
#define TYPE_OTHER
Definition: parser_wps.c:22
#define WPS_OUTPUT
Definition: parser_wps.c:32
#define min(a, b)
#define max(a, b)
const char * G_program_name(void)
Return module name.
Definition: progrm_nme.c:28
int G_snprintf(char *str, size_t size, const char *fmt,...)
snprintf() clone.
Definition: snprintf.c:43
char * G_store(const char *s)
Copy string to allocated memory.
Definition: strings.c:87