1 /*!
2 \file lib/vector/Vlib/close.c
3
4 \brief Vector library - Close vector map
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 (C) 2001-2015 by the GRASS Development Team
9
10 This program is free software under the GNU General Public License
11 (>=v2). Read the file COPYING that comes with GRASS for details.
12
13 \author Original author CERL, probably Dave Gerdes or Mike Higgins.
14 \author Update to GRASS 5.7 Radim Blazek and David D. Gray.
15 \author Update to GRASS 7 Martin Landa <landa.martin gmail.com>
16 */
17
18 #include <stdlib.h>
19 #include <stdio.h>
20 #include <string.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <unistd.h>
24
25 #include <grass/vector.h>
26 #include <grass/glocale.h>
27
28 #include "local_proto.h"
29
clo_dummy()30 static int clo_dummy()
31 {
32 return -1;
33 }
34
35 #if !defined HAVE_OGR || !defined HAVE_POSTGRES
format()36 static int format()
37 {
38 G_fatal_error(_("Requested format is not compiled in this version"));
39 return 0;
40 }
41 #endif
42
43 static int (*Close_array[][2]) () = {
44 {
45 clo_dummy, V1_close_nat}
46 #ifdef HAVE_OGR
47 , {
48 clo_dummy, V1_close_ogr}
49 , {
50 clo_dummy, V1_close_ogr}
51 #else
52 , {
53 clo_dummy, format}
54 , {
55 clo_dummy, format}
56 #endif
57 #ifdef HAVE_POSTGRES
58 , {
59 clo_dummy, V1_close_pg}
60 #else
61 , {
62 clo_dummy, format}
63 #endif
64 };
65
66 static void unlink_file(const struct Map_info *, const char *);
67
68 /*!
69 \brief Close vector map
70
71 \param Map pointer to Map_info
72
73 \return 0 on success
74 \return non-zero on error
75 */
Vect_close(struct Map_info * Map)76 int Vect_close(struct Map_info *Map)
77 {
78 int create_link; /* used for external formats only */
79 struct Coor_info CInfo;
80
81 G_debug(1, "Vect_close(): name = %s, mapset = %s, format = %d, level = %d, is_tmp = %d",
82 Map->name, Map->mapset, Map->format, Map->level, Map->temporary);
83
84 if (Map->temporary &&
85 (Map->fInfo.ogr.dsn || Map->fInfo.pg.conninfo)) {
86 /* transfer features for external output format */
87 struct Map_info Out;
88
89 putenv("GRASS_VECTOR_EXTERNAL_IMMEDIATE=1");
90 if (-1 == Vect_open_new(&Out, Vect_get_name(Map), Vect_is_3d(Map))) {
91 G_warning(_("Unable to create vector map <%s>"),
92 Vect_get_name(Map));
93 return 1;
94 }
95
96 /* copy metadata */
97 Vect_hist_copy(Map, &Out);
98 Vect_copy_head_data(Map, &Out);
99 /* copy dblinks (temporary map -> output map) to transfer
100 (input map -> output map) attributes */
101 Vect_copy_map_dblinks(Map, &Out, TRUE);
102 /* afterwords, dblinks must be removed from temporary map
103 otherwise when deleting temporary map also original
104 attribute tables would be deteled */
105 Vect_map_del_dblink(Map, -1); /* delete db links for all layers */
106
107 if (0 != Vect_copy_map_lines_field(Map, 1, &Out)) { /* always layer = 1 for OGR/PG maps */
108 G_warning(_("Copying features failed"));
109 return -1;
110 }
111
112 Vect_build(&Out);
113
114 Vect_close(&Out);
115 putenv("GRASS_VECTOR_EXTERNAL_IMMEDIATE="); /* unset variable */
116 }
117
118 /* check for external formats whether to create a link */
119 create_link = TRUE;
120 if (Map->format == GV_FORMAT_OGR ||
121 Map->format == GV_FORMAT_POSTGIS) {
122 char *def_file;
123
124 if (Map->format == GV_FORMAT_POSTGIS) {
125 if (getenv("GRASS_VECTOR_PGFILE"))
126 def_file = getenv("GRASS_VECTOR_PGFILE");
127 else
128 def_file = "PG";
129 }
130 else {
131 def_file = "OGR";
132 }
133 if (G_find_file2("", def_file, G_mapset())) {
134 FILE *fp;
135 const char *p;
136
137 struct Key_Value *key_val;
138
139 fp = G_fopen_old("", def_file, G_mapset());
140 if (!fp) {
141 G_warning(_("Unable to open %s file"), def_file);
142 }
143 else {
144 key_val = G_fread_key_value(fp);
145 fclose(fp);
146
147 /* create a vector link in the current mapset ? */
148 p = G_find_key_value("link", key_val);
149 if (p && G_strcasecmp(p, "no") == 0) {
150 create_link = FALSE;
151 }
152 else {
153 p = G_find_key_value("link_name", key_val);
154 if (p) {
155 /* use different name for a link */
156 G_free(Map->name);
157 Map->name = G_store(p);
158 }
159 }
160 }
161 }
162 }
163
164 /* store support files for vector maps in the current mapset if in
165 write mode on level 2 */
166 if (strcmp(Map->mapset, G_mapset()) == 0 &&
167 Map->support_updated &&
168 Map->plus.built == GV_BUILD_ALL &&
169 create_link) {
170
171 unlink_file(Map, GV_TOPO_ELEMENT); /* topo */
172
173 unlink_file(Map, GV_SIDX_ELEMENT); /* sidx */
174
175 unlink_file(Map, GV_CIDX_ELEMENT); /* cidx */
176
177 if (Map->format == GV_FORMAT_OGR || Map->format == GV_FORMAT_POSTGIS) {
178 unlink_file(Map, GV_FIDX_ELEMENT); /* fidx */
179 }
180
181 Vect_coor_info(Map, &CInfo);
182 Map->plus.coor_size = CInfo.size;
183 Map->plus.coor_mtime = CInfo.mtime;
184
185 /* write out topo file */
186 Vect_save_topo(Map);
187
188 /* write out sidx file */
189 Map->plus.Spidx_new = TRUE; /* force writing */
190 Vect_save_sidx(Map);
191
192 /* write out cidx file */
193 Vect_cidx_save(Map);
194
195 /* write out fidx file */
196 if (Map->format == GV_FORMAT_OGR)
197 V2_close_ogr(Map);
198 else if (Map->format == GV_FORMAT_POSTGIS)
199 V2_close_pg(Map);
200 }
201
202 /* spatial index must also be closed when opened with topo but not
203 * modified */
204 if (Map->plus.spidx_fp.file &&
205 Map->plus.Spidx_built == TRUE &&
206 !Map->support_updated &&
207 Map->plus.built == GV_BUILD_ALL) {
208
209 G_debug(1, "spatial index file closed");
210 fclose(Map->plus.spidx_fp.file);
211 }
212
213 /* release memory if required */
214 if (Map->level > 1 && Map->plus.release_support) {
215 G_debug(1, "free topology, spatial index, and category index");
216 dig_free_plus(&(Map->plus));
217 }
218
219 G_debug(1, "close history file");
220 if (Map->hist_fp)
221 fclose(Map->hist_fp);
222
223 /* close level 1 files / data sources if not head_only */
224 if (!Map->head_only) {
225 if (create_link && ((*Close_array[Map->format][1]) (Map)) != 0) {
226 G_warning(_("Unable to close vector <%s>"),
227 Vect_get_full_name(Map));
228 return 1;
229 }
230 }
231
232 G_free(Map->name);
233 G_free(Map->mapset);
234 G_free(Map->location);
235 G_free(Map->gisdbase);
236
237 Map->open = VECT_CLOSED_CODE;
238
239 return 0;
240 }
241
242 /*!
243 \brief Save format definition file for vector map
244
245 \param Map pointer to Map_info structure
246
247 \return 1 on success
248 \return 0 on error
249 */
Vect_save_frmt(struct Map_info * Map)250 int Vect_save_frmt(struct Map_info *Map)
251 {
252 FILE *fd;
253 char buf[GPATH_MAX];
254
255 if (Map->format != GV_FORMAT_OGR &&
256 Map->format != GV_FORMAT_POSTGIS) {
257 G_warning(_("Invalid request for writing frmt file - map format is %d"), Map->format);
258 return 0;
259 }
260
261 /* create frmt file */
262 sprintf(buf, "%s/%s", GV_DIRECTORY, Map->name);
263 fd = G_fopen_new(buf, GV_FRMT_ELEMENT);
264 if (fd == NULL) {
265 G_fatal_error("Unable to create file '%s'", buf);
266 }
267
268 if (Map->format == GV_FORMAT_POSTGIS) {
269 #ifdef HAVE_POSTGRES
270 fprintf(fd, "format: postgis\n");
271 fprintf(fd, "conninfo: %s\n", Map->fInfo.pg.conninfo);
272 fprintf(fd, "schema: %s\n", Map->fInfo.pg.schema_name);
273 fprintf(fd, "table: %s\n", Map->fInfo.pg.table_name);
274 #else
275 G_fatal_error(_("GRASS is not compiled with PostgreSQL support"));
276 return 0;
277 #endif
278 } else if (Map->format == GV_FORMAT_OGR) {
279 #ifdef HAVE_OGR
280 fprintf(fd, "format: ogr\n");
281 fprintf(fd, "dsn: %s\n", Map->fInfo.ogr.dsn);
282 fprintf(fd, "layer: %s\n", Map->fInfo.ogr.layer_name);
283 #else
284 G_fatal_error(_("GRASS is not compiled with OGR support"));
285 return 0;
286 #endif
287 }
288
289 G_verbose_message(_("Link to vector map <%s> created"), Map->name);
290
291 /* close frmt file */
292 fclose(fd);
293
294 return 1;
295 }
296
297 /*! Free memory of line cache
298
299 \param cache pointer to lines cache to be freed
300 */
Vect__free_cache(struct Format_info_cache * cache)301 void Vect__free_cache(struct Format_info_cache *cache) {
302 int i;
303 /* destroy lines in cache */
304 for (i = 0; i < cache->lines_alloc; i++) {
305 Vect_destroy_line_struct(cache->lines[i]);
306 }
307 G_free(cache->lines);
308 G_free(cache->lines_types);
309 G_free(cache->lines_cats);
310
311 G_zero(cache, sizeof(struct Format_info_cache));
312 }
313
314 /*! Free memory of offset array
315
316 \param cache pointer to offset array to be freed
317 */
Vect__free_offset(struct Format_info_offset * offset)318 void Vect__free_offset(struct Format_info_offset *offset)
319 {
320 G_free(offset->array);
321 G_zero(offset, sizeof(struct Format_info_offset));
322 }
323
unlink_file(const struct Map_info * Map,const char * name)324 void unlink_file(const struct Map_info *Map, const char *name)
325 {
326 char path[GPATH_MAX];
327
328 /* delete old support files if available */
329 Vect__get_element_path(path, Map, name);
330 if (access(path, F_OK) == 0) { /* file exists? */
331 G_debug(2, "\t%s: unlink", path);
332 unlink(path);
333 }
334 }
335