1 /*--------------------------------------------------------------------
2  *
3  *    Copyright (c) 2004-2021 by the GMT Team (https://www.generic-mapping-tools.org/team.html)
4  *    See README file for copying and redistribution conditions.
5  *--------------------------------------------------------------------*/
6 /*
7  * mgd77path accepts MGD77 cruise names and returns the full system
8  * path to the file(s).
9  *
10  * Author:	Paul Wessel
11  * Date:	26-AUG-2004
12  * Version:	1.0 Based on the old gmtpath.c
13  *
14  *
15  */
16 
17 #include "gmt_dev.h"
18 #include "mgd77.h"
19 
20 #define THIS_MODULE_CLASSIC_NAME	"mgd77path"
21 #define THIS_MODULE_MODERN_NAME	"mgd77path"
22 #define THIS_MODULE_LIB		"mgd77"
23 #define THIS_MODULE_PURPOSE	"Return paths to MGD77 cruises and directories"
24 #define THIS_MODULE_KEYS	">D}"
25 #define THIS_MODULE_NEEDS	""
26 #define THIS_MODULE_OPTIONS "-V"
27 
28 struct MGD77PATH_CTRL {	/* All control options for this program (except common args) */
29 	/* active is true if the option has been activated */
30 	struct MGD77PATH_A {	/* -A */
31 		bool active;
32 		bool mode;
33 	} A;
34 	struct MGD77PATH_D {	/* -D */
35 		bool active;
36 	} D;
37 	struct MGD77PATH_I {	/* -I */
38 		bool active;
39 		unsigned int n;
40 		char code[3];
41 	} I;
42 };
43 
New_Ctrl(struct GMT_CTRL * GMT)44 static void *New_Ctrl (struct GMT_CTRL *GMT) {	/* Allocate and initialize a new control structure */
45 	struct MGD77PATH_CTRL *C = NULL;
46 
47 	C = gmt_M_memory (GMT, NULL, 1, struct MGD77PATH_CTRL);
48 
49 	/* Initialize values whose defaults are not 0/false/NULL */
50 
51 	return (C);
52 }
53 
Free_Ctrl(struct GMT_CTRL * GMT,struct MGD77PATH_CTRL * C)54 static void Free_Ctrl (struct GMT_CTRL *GMT, struct MGD77PATH_CTRL *C) {	/* Deallocate control structure */
55 	if (!C) return;
56 	gmt_M_free (GMT, C);
57 }
58 
usage(struct GMTAPI_CTRL * API,int level)59 static int usage (struct GMTAPI_CTRL *API, int level) {
60 	const char *name = gmt_show_name_and_purpose (API, THIS_MODULE_LIB, THIS_MODULE_CLASSIC_NAME, THIS_MODULE_PURPOSE);
61 	if (level == GMT_MODULE_PURPOSE) return (GMT_NOERROR);
62 	GMT_Usage (API, 0, "usage: %s <cruise(s)> [-A[c]] [-D] [-Ia|c|m|t] [%s] [%s]\n", name, GMT_V_OPT, GMT_PAR_OPT);
63 
64 	if (level == GMT_SYNOPSIS) return (GMT_MODULE_SYNOPSIS);
65 
66 	GMT_Message (API, GMT_TIME_NONE, "  REQUIRED ARGUMENTS:\n");
67 	MGD77_Cruise_Explain (API->GMT);
68 	GMT_Message (API, GMT_TIME_NONE, "\n  OPTIONAL ARGUMENTS:\n");
69 	GMT_Usage (API, 1, "\n-A[c]");
70 	GMT_Usage (API, -2, "List full cruise pAths [Default].  Append c to only get cruise names.");
71 	GMT_Usage (API, 1, "\n-D List all directories with MGD77 files instead.");
72 	GMT_Usage (API, 1, "\n-Ia|c|m|t");
73 	GMT_Usage (API, -2, "Ignore certain data file formats from consideration. Append combination of acmt to ignore [Default ignores none]:");
74 	GMT_Usage (API, 3, "a: MGD77 ASCII table.");
75 	GMT_Usage (API, 3, "c: MGD77+ netCDF table.");
76 	GMT_Usage (API, 3, "m: MGD77T ASCII table.");
77 	GMT_Usage (API, 3, "t: Plain table.");
78 	GMT_Option (API, "V,.");
79 
80 	return (GMT_MODULE_USAGE);
81 }
82 
parse(struct GMT_CTRL * GMT,struct MGD77PATH_CTRL * Ctrl,struct GMT_OPTION * options)83 static int parse (struct GMT_CTRL *GMT, struct MGD77PATH_CTRL *Ctrl, struct GMT_OPTION *options) {
84 	/* This parses the options provided to mgd77path and sets parameters in CTRL.
85 	 * Any GMT common options will override values set previously by other commands.
86 	 * It also replaces any file names specified as input or output with the data ID
87 	 * returned when registering these sources/destinations with the API.
88 	 */
89 
90 	unsigned int n_errors = 0;
91 	struct GMT_OPTION *opt = NULL;
92 	struct GMTAPI_CTRL *API = GMT->parent;
93 
94 	for (opt = options; opt; opt = opt->next) {
95 		switch (opt->option) {
96 
97 			case '<':	/* Skip input files */
98 			case '#':	/* Skip input files confused as numbers (e.g. 123456) */
99 				break;
100 
101 			/* Processes program-specific parameters */
102 
103 			case 'P':
104 				if (gmt_M_compat_check (GMT, 4)) {
105 					GMT_Report (API, GMT_MSG_COMPAT, "-P is deprecated; use -A instead mext time.\n");
106 					Ctrl->A.active = true;
107 					/* Purposfully falling through to catch 'A' instead */
108 				}
109 				else {
110 					n_errors += gmt_default_error (GMT, opt->option);
111 					break;
112 				}
113 				/* Intentionally fall through */
114 			case 'A':	/* Show list of paths to MGD77 files */
115 				n_errors += gmt_M_repeated_module_option (API, Ctrl->A.active);
116 				Ctrl->A.active = true;
117 				if (opt->arg[0] == 'c' || opt->arg[0] == '-') Ctrl->A.mode = true;
118 				break;
119 
120 			case 'D':	/* Show list of directories with MGD77 files */
121 				n_errors += gmt_M_repeated_module_option (API, Ctrl->D.active);
122 				Ctrl->D.active = true;
123 				break;
124 
125 			case 'I':
126 				n_errors += gmt_M_repeated_module_option (API, Ctrl->I.active);
127 				Ctrl->I.active = true;
128 				if (Ctrl->I.n < 3) {
129 					if (strchr ("acmt", (int)opt->arg[0]))
130 						Ctrl->I.code[Ctrl->I.n++] = opt->arg[0];
131 					else {
132 						GMT_Report (API, GMT_MSG_ERROR, "Option -I Bad modifier (%c). Use -Ia|c|m|t!\n", opt->arg[0]);
133 						n_errors++;
134 					}
135 				}
136 				else {
137 					GMT_Report (API, GMT_MSG_ERROR, "Option -I: Can only be applied 0-2 times\n");
138 					n_errors++;
139 				}
140 				break;
141 
142 			default:	/* Report bad options */
143 				n_errors += gmt_default_error (GMT, opt->option);
144 				break;
145 		}
146 	}
147 	n_errors += gmt_M_check_condition (GMT, Ctrl->A.active && Ctrl->D.active, "Only one of -A -D may be used\n");
148 
149 	return (n_errors ? GMT_PARSE_ERROR : GMT_NOERROR);
150 }
151 
152 #define bailout(code) {gmt_M_free_options (mode); return (code);}
153 #define Return(code) {Free_Ctrl (GMT, Ctrl); gmt_end_module (GMT, GMT_cpy); bailout (code);}
154 
GMT_mgd77path(void * V_API,int mode,void * args)155 EXTERN_MSC int GMT_mgd77path (void *V_API, int mode, void *args) {
156 	uint64_t n_cruises = 0, i, n_paths = 0;
157 	int error = 0;
158 
159 	char path[PATH_MAX] = {""}, **list = NULL;
160 
161 	struct MGD77_CONTROL M;
162 	struct MGD77PATH_CTRL *Ctrl = NULL;
163 	struct GMT_CTRL *GMT = NULL, *GMT_cpy = NULL;
164 	struct GMT_OPTION *options = NULL;
165 	struct GMTAPI_CTRL *API = gmt_get_api_ptr (V_API);	/* Cast from void to GMTAPI_CTRL pointer */
166 
167 	/*----------------------- Standard module initialization and parsing ----------------------*/
168 
169 	if (API == NULL) return (GMT_NOT_A_SESSION);
170 	if (mode == GMT_MODULE_PURPOSE) return (usage (API, GMT_MODULE_PURPOSE));	/* Return the purpose of program */
171 	options = GMT_Create_Options (API, mode, args);	if (API->error) return (API->error);	/* Set or get option list */
172 
173 	if ((error = gmt_report_usage (API, options, 0, usage)) != GMT_NOERROR) bailout (error);	/* Give usage if requested */
174 
175 	/* Parse the command-line arguments */
176 
177 	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 */
178 	if (GMT_Parse_Common (API, THIS_MODULE_OPTIONS, options)) Return (API->error);
179 	Ctrl = New_Ctrl (GMT);	/* Allocate and initialize a new control structure */
180 	if ((error = parse (GMT, Ctrl, options)) != 0) Return (error);
181 
182 	/*---------------------------- This is the mgd77path main code ----------------------------*/
183 
184 	MGD77_Init (GMT, &M);			/* Initialize MGD77 Machinery */
185 
186 	if (Ctrl->I.active) MGD77_Process_Ignore (GMT, 'I', Ctrl->I.code);
187 
188 	if (Ctrl->D.active) {	/* Just list the current active MGD77 data directories and exit */
189 		printf ("# Currently, your $MGD77_HOME is set to: %s\n", M.MGD77_HOME);
190 		printf ("# $MGD77_HOME/mgd77_paths.txt contains these directories:\n");
191 		for (i = 0; i < M.n_MGD77_paths; i++) printf ("%s\n", M.MGD77_datadir[i]);
192 		Return (GMT_NOERROR);
193 	}
194 
195 	error = MGD77_Path_Expand (GMT, &M, options, &list);	/* Get list of requested IDs */
196 
197 	if (error <= 0) {
198 		GMT_Report (API, GMT_MSG_ERROR, "No cruises found\n");
199 		MGD77_Path_Free (GMT, n_paths, list);
200 		Return (GMT_NO_INPUT);
201 	}
202 	n_paths = (uint64_t)error;
203 
204 	for (i = 0; i < n_paths; i++) {		/* Process each ID */
205  		if (MGD77_Get_Path (GMT, path, list[i], &M))
206 			GMT_Report (API, GMT_MSG_ERROR, "Cannot find cruise %s\n", list[i]);
207 		else if (Ctrl->A.mode) {
208 			printf ("%s\n", list[i]);
209 			n_cruises++;
210 		}
211 		else {
212 			printf ("%s\n", path);
213 			n_cruises++;
214 		}
215 	}
216 
217 	GMT_Report (API, GMT_MSG_INFORMATION, "Found %" PRIu64 " cruises\n", n_cruises);
218 
219 	MGD77_Path_Free (GMT, n_paths, list);
220 	MGD77_end (GMT, &M);
221 
222 	Return (GMT_NOERROR);
223 }
224