1 /*--------------------------------------------------------------------
2  *
3  *	Copyright (c) 1991-2021 by the GMT Team (https://www.generic-mapping-tools.org/team.html)
4  *	See LICENSE.TXT file for copying and redistribution conditions.
5  *
6  *	This program is free software; you can redistribute it and/or modify
7  *	it under the terms of the GNU Lesser General Public License as published by
8  *	the Free Software Foundation; version 3 or any later version.
9  *
10  *	This program is distributed in the hope that it will be useful,
11  *	but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *	GNU Lesser General Public License for more details.
14  *
15  *	Contact info: www.generic-mapping-tools.org
16  *--------------------------------------------------------------------*/
17 /*
18  * Author:	Paul Wessel
19  * Date:	2-May-2013
20  * Version:	6 API
21  *
22  * Brief synopsis: gmt write lets us (read from memory and) write any of the 6 GMT resources.
23  *
24  */
25 
26 #include "gmt_dev.h"
27 
28 #define THIS_MODULE_CLASSIC_NAME	"gmtwrite"
29 #define THIS_MODULE_MODERN_NAME	"gmtwrite"
30 #define THIS_MODULE_LIB		"core"
31 #define THIS_MODULE_PURPOSE	"Write GMT objects from external API"
32 #define THIS_MODULE_KEYS	"-T-,<?{,>?}"
33 #define THIS_MODULE_NEEDS	""
34 #define THIS_MODULE_OPTIONS "->RV"
35 
36 /* Control structure for gmtwrite */
37 
38 struct GMTWRITE_CTRL {
39 	struct GMTWRITE_IO {	/* Need two args with filenames */
40 		bool active[2];
41 		char *file[2];
42 	} IO;
43 	struct GMTWRITE_T {	/* -T sets data type */
44 		bool active;
45 		enum GMT_enum_family mode;
46 	} T;
47 };
48 
New_Ctrl(struct GMT_CTRL * GMT)49 static void *New_Ctrl (struct GMT_CTRL *GMT) {	/* Allocate and initialize a new control structure */
50 	struct GMTWRITE_CTRL *C;
51 
52 	C = gmt_M_memory (GMT, NULL, 1, struct GMTWRITE_CTRL);
53 
54 	/* Initialize values whose defaults are not 0/false/NULL */
55 
56 	return (C);
57 }
58 
Free_Ctrl(struct GMT_CTRL * GMT,struct GMTWRITE_CTRL * C)59 static void Free_Ctrl (struct GMT_CTRL *GMT, struct GMTWRITE_CTRL *C) {	/* Deallocate control structure */
60 	if (!C) return;
61 	gmt_M_str_free (C->IO.file[GMT_IN]);
62 	gmt_M_str_free (C->IO.file[GMT_OUT]);
63 	gmt_M_free (GMT, C);
64 }
65 
usage(struct GMTAPI_CTRL * API,int level)66 static int usage (struct GMTAPI_CTRL *API, int level) {
67 	const char *name = gmt_show_name_and_purpose (API, THIS_MODULE_LIB, THIS_MODULE_CLASSIC_NAME, THIS_MODULE_PURPOSE);
68 	if (level == GMT_MODULE_PURPOSE) return (GMT_NOERROR);
69 	GMT_Message (API, GMT_TIME_NONE, "usage: %s <infile> <outfile> -Tc|d|g|i|p|u [%s] [%s]\n", name, GMT_Rx_OPT, GMT_V_OPT);
70 
71 	if (level == GMT_SYNOPSIS) return (GMT_MODULE_SYNOPSIS);
72 
73 	GMT_Message (API, GMT_TIME_NONE, "\t   Specify input and output file names\n");
74 	GMT_Message (API, GMT_TIME_NONE, "\t-T Specify data type.  Choose among:\n");
75 	GMT_Message (API, GMT_TIME_NONE, "\t   c : CPT\n");
76 	GMT_Message (API, GMT_TIME_NONE, "\t   d : Dataset\n");
77 	GMT_Message (API, GMT_TIME_NONE, "\t   g : Grid\n");
78 	GMT_Message (API, GMT_TIME_NONE, "\t   i : Image\n");
79 	GMT_Message (API, GMT_TIME_NONE, "\t   p : PostScript\n");
80 	GMT_Message (API, GMT_TIME_NONE, "\t   u : Cube\n");
81 	GMT_Message (API, GMT_TIME_NONE, "\n  OPTIONAL ARGUMENTS:\n");
82 	GMT_Option (API, "R,V,.");
83 
84 	return (GMT_MODULE_USAGE);
85 }
86 
parse(struct GMT_CTRL * GMT,struct GMTWRITE_CTRL * Ctrl,struct GMT_OPTION * options)87 static int parse (struct GMT_CTRL *GMT, struct GMTWRITE_CTRL *Ctrl, struct GMT_OPTION *options) {
88 
89 	/* This parses the options provided to grdwrite and sets parameters in CTRL.
90 	 * Any GMT common options will override values set previously by other commands.
91 	 * It also replaces any file names specified as input or output with the data ID
92 	 * returned when registering these sources/destinations with the API.
93 	 */
94 
95 	unsigned int n_errors = 0, n_files = 0;
96 	struct GMT_OPTION *opt = NULL;
97 	struct GMTAPI_CTRL *API = GMT->parent;
98 
99 	for (opt = options; opt; opt = opt->next) {	/* Process all the options given */
100 
101 		switch (opt->option) {
102 			/* Processes program-specific parameters */
103 
104 			case GMT_OPT_INFILE:	/* File args */
105 				if (Ctrl->IO.active[GMT_OUT]) {	/* User gave output as ->outfile and it was found on the command line earlier */
106 					n_errors += gmt_M_repeated_module_option (API, Ctrl->IO.active[GMT_IN]);
107 					Ctrl->IO.active[GMT_IN] = true;
108 					Ctrl->IO.file[GMT_IN] = strdup (opt->arg);
109 				}
110 				else if (n_files < 2) {	/* Encountered input file(s); the 2nd would be output */
111 					n_errors += gmt_M_repeated_module_option (API, Ctrl->IO.active[n_files]);
112 					Ctrl->IO.active[n_files] = true;
113 					Ctrl->IO.file[n_files] = strdup (opt->arg);
114 				}
115 				n_files++;
116 				break;
117 			case GMT_OPT_OUTFILE:	/* Got specific output argument */
118 				n_errors += gmt_M_repeated_module_option (API, Ctrl->IO.active[GMT_OUT]);
119 				Ctrl->IO.active[GMT_OUT] = true;
120 				Ctrl->IO.file[GMT_OUT] = strdup (opt->arg);
121 				n_files++;
122 				break;
123 			case 'T':	/* Type */
124 				n_errors += gmt_M_repeated_module_option (API, Ctrl->T.active);
125 				Ctrl->T.active = true;
126 				switch (opt->arg[0]) {
127 					case 't':
128 						if (gmt_M_compat_check (GMT, 5))	/* There is no longer a T type but we will honor T as D from GMT5 */
129 							Ctrl->T.mode = GMT_IS_DATASET;
130 						else {
131 							GMT_Report (API, GMT_MSG_ERROR, "Unrecognized data type %c.  Choose from c, d, g, i, p, and u\n", opt->arg[0]);
132 							n_errors++;
133 						}
134 						break;
135 					case 'd': Ctrl->T.mode = GMT_IS_DATASET; break;
136 					case 'g': Ctrl->T.mode = GMT_IS_GRID;	 break;
137 					case 'c': Ctrl->T.mode = GMT_IS_PALETTE;	 break;
138 					case 'i': Ctrl->T.mode = GMT_IS_IMAGE;	 break;
139 					case 'p': Ctrl->T.mode = GMT_IS_POSTSCRIPT;	 break;
140 					case 'u': Ctrl->T.mode = GMT_IS_CUBE;	 break;
141 					default:
142 						GMT_Report (API, GMT_MSG_ERROR, "Unrecognized data type %c.  Choose from c, d, g, i, p, and u\n", opt->arg[0]);
143 						n_errors++;
144 						break;
145 				}
146 				break;
147 
148 			default:	/* Report bad options */
149 				n_errors += gmt_default_error (GMT, opt->option);
150 				break;
151 		}
152 	}
153 
154 	n_errors += gmt_M_check_condition (GMT, !(Ctrl->IO.active[GMT_IN] && Ctrl->IO.active[GMT_OUT]), "Must specify both input and output filenames\n");
155 	n_errors += gmt_M_check_condition (GMT, Ctrl->IO.active[GMT_IN] && (!Ctrl->IO.file[GMT_IN] || !Ctrl->IO.file[GMT_IN][0]), "Must specify input filename\n");
156 	n_errors += gmt_M_check_condition (GMT, Ctrl->IO.active[GMT_OUT] && (!Ctrl->IO.file[GMT_OUT] || !Ctrl->IO.file[GMT_OUT][0]), "Must specify output filename\n");
157 	n_errors += gmt_M_check_condition (GMT, n_files != 2, "Must specify only two filenames (input and output)\n");
158 	n_errors += gmt_M_check_condition (GMT, !Ctrl->T.active, "Option -T: Must specify a valid datatype\n");
159 
160 	return (n_errors ? GMT_PARSE_ERROR : GMT_NOERROR);
161 }
162 
163 #define bailout(code) {gmt_M_free_options (mode); return (code);}
164 #define Return(code) {Free_Ctrl (GMT, Ctrl); gmt_end_module (GMT, GMT_cpy); bailout (code);}
165 
GMT_gmtwrite(void * V_API,int mode,void * args)166 EXTERN_MSC int GMT_gmtwrite (void *V_API, int mode, void *args) {
167 	int error = 0;
168 	struct GMTWRITE_CTRL *Ctrl = NULL;
169 	struct GMT_CTRL *GMT = NULL, *GMT_cpy = NULL;
170 	struct GMT_OPTION *options = NULL;
171 	struct GMTAPI_CTRL *API = gmt_get_api_ptr (V_API);	/* Cast from void to GMTAPI_CTRL pointer */
172 
173 	/*----------------------- Standard module initialization and parsing ----------------------*/
174 
175 	if (API == NULL) return (GMT_NOT_A_SESSION);
176 	if (mode == GMT_MODULE_PURPOSE) return (usage (API, GMT_MODULE_PURPOSE));	/* Return the purpose of program */
177 	options = GMT_Create_Options (API, mode, args);	if (API->error) return (API->error);	/* Set or get option list */
178 
179 	if ((error = gmt_report_usage (API, options, 0, usage)) != GMT_NOERROR) bailout (error);	/* Give usage if requested */
180 
181 	/* Parse the command-line arguments */
182 
183 	if ((GMT = gmt_init_module (API, THIS_MODULE_LIB, THIS_MODULE_CLASSIC_NAME, THIS_MODULE_KEYS, THIS_MODULE_NEEDS, NULL, &options, &GMT_cpy)) == NULL) bailout (API->error); /* Save current state */
184 	if (GMT_Parse_Common (API, THIS_MODULE_OPTIONS, options)) Return (API->error);
185 	Ctrl = New_Ctrl (GMT);	/* Allocate and initialize a new control structure */
186 	if ((error = parse (GMT, Ctrl, options)) != 0) Return (error);
187 
188 	/*---------------------------- This is the gmtwrite main code ----------------------------*/
189 
190 	error = gmt_copy (API, Ctrl->T.mode, GMT_OUT, Ctrl->IO.file[GMT_IN], Ctrl->IO.file[GMT_OUT]);
191 	Return (error);
192 }
193