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