GRASS 8 Programmer's Manual 8.6.0dev(2026)-ddeab64dbf
Loading...
Searching...
No Matches
map.c
Go to the documentation of this file.
1/*!
2 \file lib/vector/Vlib/map.c
3
4 \brief Vector library - Manipulate vector map (copy, rename, delete)
5
6 Higher level functions for reading/writing/manipulating vectors.
7
8 (C) 2001-2009, 2012 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 */
16
17#include <stdlib.h>
18#include <stdio.h>
19#include <dirent.h>
20#include <string.h>
21#include <unistd.h>
22#include <sys/types.h>
23#include <sys/stat.h>
24#include <fcntl.h>
25#include <errno.h>
26
27#include <grass/glocale.h>
28#include <grass/vector.h>
29#include <grass/dbmi.h>
30#include <grass/glocale.h>
31
32#include "local_proto.h"
33
34/*!
35 \brief Creates and initializes Map_info structure
36
37 To free allocated memory call Vect_destroy_map_struct().
38
39 \return pointer to Map_info
40 */
42{
43 struct Map_info *p;
44
45 p = (struct Map_info *)malloc(sizeof(struct Map_info));
46
47 if (NULL == p)
48 G_fatal_error("Vect_new_map_struct(): %s", _("Out of memory"));
49
50 G_zero(p, sizeof(struct Map_info));
51
52 return p;
53}
54
55/*!
56 \brief Frees all memory associated with a Map_info structure,
57 including the structure itself
58
59 \param p pointer to Map_info structure
60 */
62{
63 /* We should free all allocated member structures, but they may be already
64 freed by other functions (e.g. Vect_close()) without resetting member
65 pointers to zero */
66
67 G_free((char *)p);
68}
69
70/*!
71 \brief Copy file
72
73 \param src source file
74 \param[out] dst destination file
75
76 \return 0 OK
77 \return 1 error
78 */
79static int copy_file(const char *src, const char *dst)
80{
81 char buf[4096];
82 int fd, fd2;
83 FILE *f2;
84 int len, len2;
85
86 if ((fd = open(src, O_RDONLY)) < 0)
87 return 1;
88
89 /* if((fd2 = open(dst, O_CREAT|O_TRUNC|O_WRONLY)) < 0) { */
90 if ((f2 = fopen(dst, "w")) == NULL) {
91 close(fd);
92 return 1;
93 }
94
95 fd2 = fileno(f2);
96
97 len2 = 0;
98 while ((len = read(fd, buf, 4096)) > 0) {
99 while (len && (len2 = write(fd2, buf, len)) >= 0)
100 len -= len2;
101 }
102
103 close(fd);
104 /* close(fd2); */
105 fclose(f2);
106
107 if (len == -1 || len2 == -1)
108 return 1;
109
110 return 0;
111}
112
113/*!
114 \brief Copy vector map including attribute tables
115
116 Note: Output vector map is overwritten if exists!
117
118 \param in name if vector map to be copied
119 \param mapset mapset name where the input map is located
120 \param out name for output vector map (new map is created in current mapset)
121
122 \return -1 error
123 \return 0 success
124 */
125int Vect_copy(const char *in, const char *mapset, const char *out)
126{
127 int i, ret;
128 struct Map_info In, Out;
130
131 const char *files[] = {
134 const char *inmapset;
136
137 G_debug(2, "Copy vector '%s' in '%s' to '%s'", in, mapset, out);
138 /* check for [A-Za-z][A-Za-z0-9_]* in name */
139 if (Vect_legal_filename(out) < 0)
140 G_fatal_error(_("Vector map name is not SQL compliant"));
141
143 if (!inmapset) {
144 G_warning(_("Unable to find vector map <%s> in <%s>"), in, mapset);
145 return -1;
146 }
148
149 /* remove mapset from fully qualified name, confuses G_file_name() */
151 in = xname;
152 }
153
154 /* Delete old vector if it exists */
155 if (G_find_vector2(out, G_mapset())) {
156 G_warning(_("Vector map <%s> already exists and will be overwritten"),
157 out);
159 if (ret != 0) {
160 G_warning(_("Unable to delete vector map <%s>"), out);
161 return -1;
162 }
163 }
164
165 /* Copy the directory */
167
168 i = 0;
169 while (files[i]) {
170 snprintf(buf, sizeof(buf), "%s/%s", in, files[i]);
172 snprintf(buf, sizeof(buf), "%s/%s", out, files[i]);
174
175 if (access(old_path, F_OK) == 0) { /* file exists? */
176 G_debug(2, "copy %s to %s", old_path, new_path);
177 if (copy_file(old_path, new_path)) {
178 G_warning(_("Unable to copy vector map <%s> to <%s>"), old_path,
179 new_path);
180 }
181 }
182 i++;
183 }
184
187
188 /* Open input */
190 if (Vect_open_old_head(&In, in, mapset) < 0)
191 G_fatal_error(_("Unable to open vector map <%s>"), in);
192
193 if (In.format != GV_FORMAT_NATIVE) { /* Done */
194 Vect_close(&In);
195 return 0;
196 }
197
198 /* Open output */
200 if (Vect_open_update_head(&Out, out, G_mapset()) < 0)
201 G_fatal_error(_("Unable to open vector map <%s>"), out);
202
203 /* Copy tables */
204 if (Vect_copy_tables(&In, &Out, 0) != 0) {
205 Vect_close(&In);
206 Vect_close(&Out);
207
208 return 1;
209 }
210
211 Vect_close(&In);
212 Vect_close(&Out);
213
214 return 0;
215}
216
217/*!
218 \brief Rename existing vector map (in the current mapset).
219
220 Attribute tables are created in the same database where input tables were
221 stored.
222
223 The original format (native/OGR) is used.
224
225 Note: Output vector map is overwritten if exists!
226
227 \param in name of vector map to be renamed
228 \param out name for output vector map
229
230 \return -1 error
231 \return 0 success
232 */
233int Vect_rename(const char *in, const char *out)
234{
235 int i, n, ret, type;
236 struct Map_info Map;
237 struct field_info *Fin, *Fout;
238 int *fields;
241
242 G_debug(2, "Rename vector '%s' to '%s'", in, out);
243 /* check for [A-Za-z][A-Za-z0-9_]* in name */
244 if (Vect_legal_filename(out) < 0)
245 G_fatal_error(_("Vector map name is not SQL compliant"));
246
247 /* Delete old vector if it exists */
248 if (G_find_vector2(out, G_mapset())) {
249 G_warning(_("Vector map <%s> already exists and will be overwritten"),
250 out);
252 }
253
254 /* remove mapset from fully qualified name */
256 in = xname;
257 }
258
259 /* Move the directory */
261
262 if (ret == 0) {
263 G_warning(_("Vector map <%s> not found"), in);
264 return -1;
265 }
266 else if (ret == -1) {
267 G_warning(_("Unable to copy vector map <%s> to <%s>"), in, out);
268 return -1;
269 }
270
271 /* Rename all tables if the format is native */
274 G_fatal_error(_("Unable to open vector map <%s>"), out);
275
276 if (Map.format != GV_FORMAT_NATIVE) { /* Done */
277 Vect_close(&Map);
278 return 0;
279 }
280
281 /* Copy tables */
283 type = GV_1TABLE;
284 if (n > 1)
285 type = GV_MTABLE;
286
287 /* Make the list of fields */
288 fields = (int *)G_malloc(n * sizeof(int));
289
290 for (i = 0; i < n; i++) {
291 Fin = Vect_get_dblink(&Map, i);
292 fields[i] = Fin->number;
293 }
294
295 for (i = 0; i < n; i++) {
296 G_debug(3, "field[%d] = %d", i, fields[i]);
297
298 Fin = Vect_get_field(&Map, fields[i]);
299 if (Fin == NULL) {
300 G_warning(_("Database connection not defined for layer %d"),
301 fields[i]);
302 Vect_close(&Map);
303 return -1;
304 }
305
306 Fout = Vect_default_field_info(&Map, Fin->number, Fin->name, type);
307 G_debug(3, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'", Fin->driver,
308 Fin->database, Fin->table, Fout->driver, Fout->database,
309 Fout->table);
310
311 /* TODO: db_rename_table instead of db_copy_table */
312 ret =
313 db_copy_table(Fin->driver, Fin->database, Fin->table, Fout->driver,
314 Vect_subst_var(Fout->database, &Map), Fout->table);
315
316 if (ret == DB_FAILED) {
317 G_warning(_("Unable to copy table <%s>"), Fin->table);
318 Vect_close(&Map);
319 return -1;
320 }
321
322 /* Change the link */
323 Vect_map_del_dblink(&Map, Fin->number);
324
325 Vect_map_add_dblink(&Map, Fout->number, Fout->name, Fout->table,
326 Fin->key, Fout->database, Fout->driver);
327
328 /* Delete old table */
329 ret = db_delete_table(Fin->driver, Fin->database, Fin->table);
330 if (ret == DB_FAILED) {
331 G_warning(_("Unable to delete table <%s>"), Fin->table);
332 Vect_close(&Map);
333 return -1;
334 }
335
337 Fout->driver, Vect_subst_var(Fout->database, &Map));
338 if (driver == NULL) {
339 G_warning(_("Unable to open database <%s> by driver <%s>"),
340 Fout->database, Fout->driver);
341 }
342 else {
343 if (db_create_index2(driver, Fout->table, Fin->key) != DB_OK)
344 G_warning(_("Unable to create index for table <%s>, key <%s>"),
345 Fout->table, Fout->key);
346
348 }
349 }
350
351 Vect_close(&Map);
352 G_free(fields);
353
354 return 0;
355}
356
357/*!
358 \brief Delete vector map including attribute tables
359
360 Vector map must be located in current mapset.
361
362 \param map name of vector map to be delete
363
364 \return -1 error
365 \return 0 success
366 */
367int Vect_delete(const char *map)
368{
369 return Vect__delete(map, FALSE);
370}
371
372/*!
373 \brief Delete vector map (internal use only)
374
375 \param map name of vector map to be delete
376 \param is_tmp TRUE for temporary maps
377
378 \return -1 error
379 \return 0 success
380 */
381int Vect__delete(const char *map, int is_tmp)
382{
383 int ret;
386 const char *tmp, *mapset, *env;
387
388 struct Map_info Map;
389
390 DIR *dir;
391 struct dirent *ent;
392
393 G_debug(3, "Delete vector '%s' (is_tmp = %d)", map, is_tmp);
394
395 mapset = G_mapset();
396
397 /* remove mapset from fully qualified name */
399 if (strcmp(mapset, xmapset) != 0)
400 G_warning(_("Ignoring invalid mapset: %s"), xmapset);
401 map = xname;
402 }
403
404 if (map == NULL || strlen(map) == 0) {
405 G_warning(_("Invalid vector map name <%s>"), map ? map : "null");
406 return -1;
407 }
408
409 Vect_set_open_level(1); /* Topo not needed */
410 ret = Vect__open_old(&Map, map, mapset, NULL, FALSE, TRUE, is_tmp);
411 if (ret < 1) {
412 if (is_tmp)
413 return 0; /* temporary vector map doesn't exist */
414 else {
415 G_warning(_("Unable to open header file for vector map <%s>"), map);
416 return -1;
417 }
418 }
419
421 G_debug(1, "dbln file: %s", path);
422
423 if (access(path, F_OK) == 0) {
424 int i, n;
425 struct field_info *Fi;
426
427 /* Delete all tables, NOT external (OGR) */
428 if (Map.format == GV_FORMAT_NATIVE) {
430 for (i = 0; i < n; i++) {
431 Fi = Vect_get_dblink(&Map, i);
432 if (Fi == NULL) {
433 G_warning(_("Database connection not defined for layer %d"),
434 Map.dblnk->field[i].number);
435 /*
436 Vect_close(&Map);
437 return -1;
438 */
439 continue;
440 }
441 G_debug(3, "Delete drv:db:table '%s:%s:%s'", Fi->driver,
442 Fi->database, Fi->table);
443
444 ret = db_table_exists(Fi->driver, Fi->database, Fi->table);
445 if (ret == -1) {
446 G_warning(_("Unable to find table <%s> linked to vector "
447 "map <%s>"),
448 Fi->table, map);
449 /*
450 Vect_close(&Map);
451 return -1;
452 */
453 continue;
454 }
455
456 if (ret == 1) {
457 ret = db_delete_table(Fi->driver, Fi->database, Fi->table);
458 if (ret == DB_FAILED) {
459 G_warning(_("Unable to delete table <%s>"), Fi->table);
460 /*
461 Vect_close(&Map);
462 return -1;
463 */
464 continue;
465 }
466 }
467 else {
468 G_warning(_("Table <%s> linked to vector map <%s> does not "
469 "exist"),
470 Fi->table, map);
471 }
472 }
473 }
474 }
475
476 /* Delete all files from vector/name directory */
478 Vect_close(&Map);
479 G_debug(3, "opendir '%s'", path);
480 dir = opendir(path);
481 if (dir == NULL) {
482 G_warning(_("Unable to open directory '%s'"), path);
483 return -1;
484 }
485
486 while ((ent = readdir(dir))) {
487 G_debug(3, "file = '%s'", ent->d_name);
488 if ((strcmp(ent->d_name, ".") == 0) || (strcmp(ent->d_name, "..") == 0))
489 continue;
490
491 ret = snprintf(path_buf, GPATH_MAX, "%s/%s", path, ent->d_name);
492 if (ret >= GPATH_MAX) {
493 G_warning(_("Filepath '%s/%s' exceeds max length"), path,
494 ent->d_name);
495 closedir(dir);
496 return -1;
497 }
498 G_debug(3, "delete file '%s'", path_buf);
500 if (ret == -1) {
501 G_warning(_("Unable to delete file '%s'"), path_buf);
502 closedir(dir);
503 return -1;
504 }
505 }
506 closedir(dir);
507
508 env = getenv("GRASS_VECTOR_TMPDIR_MAPSET");
509 if (env && strcmp(env, "0") == 0) {
510 tmp = path;
511 }
512 else {
513 /* NFS can create .nfsxxxxxxxx files for those deleted
514 * -> we have to move the directory to ./tmp before it is deleted */
515 tmp = G_tempfile();
516
517 G_debug(3, "rename '%s' to '%s'", path, tmp);
518
519 ret = rename(path, tmp);
520 if (ret == -1) {
521 G_warning(_("Unable to rename directory '%s' to '%s'"), path, tmp);
522 return -1;
523 }
524 }
525
526 G_debug(3, "remove directory '%s'", tmp);
527 /* Warning: remove() fails on Windows */
528 ret = rmdir(tmp);
529 if (ret == -1) {
530 G_warning(_("Unable to remove directory '%s': %s"), tmp,
531 strerror(errno));
532 return -1;
533 }
534
535 return 0;
536}
537
538/*!
539 \brief Set spatial index to be released when vector is closed.
540
541 By default, the memory occupied by spatial index is not released.
542
543 \param Map vector map
544 */
546{
547 Map->plus.release_support = TRUE;
548}
549
550/*!
551 \brief Set category index to be updated when vector is changed.
552
553 By default, category index is not updated if vector is changed,
554 this function sets category index update.
555
556 WARNING: currently only category for elements is updated not for
557 areas
558
559 \param Map vector map
560 */
562{
563 Map->plus.update_cidx = TRUE;
564}
#define NULL
Definition ccmath.h:32
AMI_err name(char **stream_name)
Definition ami_stream.h:426
Main header of GRASS DataBase Management Interface.
#define DB_FAILED
Definition dbmi.h:72
#define DB_OK
Definition dbmi.h:71
int db_delete_table(const char *, const char *, const char *)
Delete table.
Definition delete_tab.c:29
int db_close_database_shutdown_driver(dbDriver *)
Close driver/database connection.
Definition db.c:61
int db_create_index2(dbDriver *, const char *, const char *)
Create unique index.
int db_table_exists(const char *, const char *, const char *)
Check if table exists.
dbDriver * db_start_driver_open_database(const char *, const char *)
Open driver/database connection.
Definition db.c:28
int db_copy_table(const char *, const char *, const char *, const char *, const char *, const char *)
Copy a table.
Definition copy_tab.c:443
int G_name_is_fully_qualified(const char *, char *, char *)
Check if map name is fully qualified (map @ mapset)
Definition nme_in_mps.c:36
void G_zero(void *, int)
Zero out a buffer, buf, of length i.
Definition gis/zero.c:23
void G_free(void *)
Free allocated memory.
Definition gis/alloc.c:147
void void void void G_fatal_error(const char *,...) __attribute__((format(printf
void G_warning(const char *,...) __attribute__((format(printf
int G_make_mapset_dir_object(const char *, const char *)
Create directory for an object of a given type.
Definition mapset_msc.c:109
#define G_malloc(n)
Definition defs/gis.h:139
char * G_file_name(char *, const char *, const char *, const char *)
Builds full path names to GIS data files.
Definition file_name.c:61
char * G_tempfile(void)
Returns a temporary file name.
Definition tempfile.c:62
int G_debug(int, const char *,...) __attribute__((format(printf
const char * G_find_vector2(const char *, const char *)
Find a vector map (look but don't touch)
Definition find_vect.c:62
const char * G_mapset(void)
Get current mapset name.
Definition gis/mapset.c:33
int G_rename(const char *, const char *, const char *)
Rename a database file.
Definition rename.c:69
struct field_info * Vect_default_field_info(struct Map_info *, int, const char *, int)
Get default information about link to database for new dblink.
Definition field.c:353
char * Vect_subst_var(const char *, struct Map_info *)
Substitute variable in string.
Definition field.c:923
int Vect_map_del_dblink(struct Map_info *, int)
Delete db connection from Map_info structure.
Definition field.c:155
int Vect_close(struct Map_info *)
Close vector map.
struct field_info * Vect_get_field(struct Map_info *, int)
Get information about link to database (by layer number)
Definition field.c:510
int Vect_open_update_head(struct Map_info *, const char *, const char *)
Open header file of existing vector map for updating (mostly for database link updates)
int Vect_legal_filename(const char *)
Check if output is legal vector name.
Definition legal_vname.c:31
struct field_info * Vect_get_dblink(struct Map_info *, int)
Get information about link to database.
Definition field.c:470
int Vect_get_num_dblinks(struct Map_info *)
Get number of defined dblinks.
Definition level_two.c:159
int Vect_map_add_dblink(struct Map_info *, int, const char *, const char *, const char *, const char *, const char *)
Add new db connection to Map_info structure.
Definition field.c:115
int Vect_set_open_level(int)
Predetermine level at which a vector map will be opened for reading.
int Vect_open_old_head(struct Map_info *, const char *, const char *)
Reads only info about vector map (headers)
int Vect_copy_tables(struct Map_info *, struct Map_info *, int)
Copy attribute tables linked to vector map.
#define GV_FRMT_ELEMENT
Format description, data location (OGR)
Definition dig_defines.h:10
#define GV_DIRECTORY
Name of vector directory.
Definition dig_defines.h:8
#define GV_SIDX_ELEMENT
Native format, spatial index.
Definition dig_defines.h:22
#define GV_1TABLE
One table linked to vector map.
Definition dig_defines.h:99
#define GV_COOR_ELEMENT
Native format, coordinates.
Definition dig_defines.h:12
#define GV_DBLN_ELEMENT
Native format, link to database.
Definition dig_defines.h:16
#define GV_CIDX_ELEMENT
Native format, category index.
Definition dig_defines.h:24
#define GV_TOPO_ELEMENT
Native format, topology file.
Definition dig_defines.h:20
#define GV_MTABLE
More tables linked to vector map.
#define GV_HEAD_ELEMENT
Native format, header information.
Definition dig_defines.h:14
#define GV_FORMAT_NATIVE
Geometry data formats supported by lib Don't change GV_FORMAT_* values, this order is hardcoded in li...
Definition dig_defines.h:83
#define GV_HIST_ELEMENT
Native format, history file.
Definition dig_defines.h:18
struct DIR DIR
Definition dirent.h:18
Header file for msvc/fcntl.c.
#define open
Definition fcntl.h:33
#define GMAPSET_MAX
Definition gis.h:197
#define GPATH_MAX
Definition gis.h:199
#define TRUE
Definition gis.h:78
#define FALSE
Definition gis.h:82
#define GNAME_MAX
Definition gis.h:196
#define _(str)
Definition glocale.h:10
void Vect_set_category_index_update(struct Map_info *Map)
Set category index to be updated when vector is changed.
Definition map.c:561
void Vect_destroy_map_struct(struct Map_info *p)
Frees all memory associated with a Map_info structure, including the structure itself.
Definition map.c:61
int Vect__delete(const char *map, int is_tmp)
Delete vector map (internal use only)
Definition map.c:381
int Vect_rename(const char *in, const char *out)
Rename existing vector map (in the current mapset).
Definition map.c:233
int Vect_copy(const char *in, const char *mapset, const char *out)
Copy vector map including attribute tables.
Definition map.c:125
struct Map_info * Vect_new_map_struct(void)
Creates and initializes Map_info structure.
Definition map.c:41
void Vect_set_release_support(struct Map_info *Map)
Set spatial index to be released when vector is closed.
Definition map.c:545
int Vect_delete(const char *map)
Delete vector map including attribute tables.
Definition map.c:367
DIR * opendir(const char *name)
Definition msvc/dirent.c:15
struct dirent * readdir(DIR *dir)
Definition msvc/dirent.c:75
int closedir(DIR *dir)
Definition msvc/dirent.c:54
void * malloc(unsigned)
Vector map info.
char * mapset
Mapset name.
int type
Feature type constraint.
int format
Map format (native, ogr, postgis)
Layer (old: field) information.
char * driver
Name of DB driver ('sqlite', 'dbf', ...)
Definition path.h:15
#define unlink
Definition unistd.h:11
#define access
Definition unistd.h:7
#define read
Definition unistd.h:5
#define rmdir
Definition unistd.h:15
#define close
Definition unistd.h:8
#define write
Definition unistd.h:6
#define F_OK
Definition unistd.h:22
int Vect__open_old(struct Map_info *Map, const char *name, const char *mapset, const char *layer, int update, int head_only, int is_tmp)
Open existing vector map for reading (internal use only)
char * Vect__get_element_path(char *file_path, struct Map_info *Map, const char *element)
Get map element full path (internal use only)