GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
map.c
Go to the documentation of this file.
00001 
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <dirent.h>
00024 #include <string.h>
00025 #include <unistd.h>
00026 #include <errno.h>
00027 #include <sys/types.h>
00028 #include <sys/stat.h>
00029 #include <fcntl.h>
00030 #include <grass/glocale.h>
00031 #include <grass/gis.h>
00032 #include <grass/Vect.h>
00033 #include <grass/dbmi.h>
00034 #include <grass/glocale.h>
00035 
00045 int Vect_copy_map_lines(struct Map_info *In, struct Map_info *Out)
00046 {
00047     int i, type, nlines, ret;
00048     struct line_pnts *Points;
00049     struct line_cats *Cats;
00050 
00051     Points = Vect_new_line_struct();
00052     Cats = Vect_new_cats_struct();
00053 
00054     if (Vect_level(In) < 1)
00055         G_fatal_error("Vect_copy_map_lines(): %s",
00056                       _("input vector map is not open"));
00057 
00058     ret = 0;
00059     /* Note: sometimes is important to copy on level 2 (pseudotopo centroids) 
00060      *       and sometimes on level 1 if build take too long time */
00061     if (Vect_level(In) >= 2) {
00062         nlines = Vect_get_num_lines(In);
00063         for (i = 1; i <= nlines; i++) {
00064             if (!Vect_line_alive(In, i))
00065                 continue;
00066 
00067             type = Vect_read_line(In, Points, Cats, i);
00068             if (type == -1) {
00069                 G_warning(_("Unable to read vector map <%s>"),
00070                           Vect_get_full_name(In));
00071                 ret = 1;
00072                 break;
00073             }
00074             if (type == 0)
00075                 continue;       /* dead line */
00076 
00077             Vect_write_line(Out, type, Points, Cats);
00078         }
00079     }
00080     else {                      /* Level 1 */
00081         Vect_rewind(In);
00082         while (1) {
00083             type = Vect_read_next_line(In, Points, Cats);
00084             if (type == -1) {
00085                 G_warning(_("Unable to read vector map <%s>"),
00086                           Vect_get_full_name(In));
00087                 ret = 1;
00088                 break;
00089             }
00090             else if (type == -2) {      /* EOF */
00091                 break;
00092             }
00093             else if (type == 0) {       /* dead line */
00094                 continue;
00095             }
00096             Vect_write_line(Out, type, Points, Cats);
00097         }
00098     }
00099     Vect_destroy_line_struct(Points);
00100     Vect_destroy_cats_struct(Cats);
00101 
00102     return ret;
00103 }
00104 
00105 /*
00106    \brief Copy file
00107 
00108    \param[in] src source file
00109    \param[out] dst destination file
00110 
00111    \return 0 OK
00112    \return 1 error
00113  */
00114 static int copy_file(const char *src, const char *dst)
00115 {
00116     char buf[1024];
00117     int fd, fd2;
00118     FILE *f2;
00119     int len, len2;
00120 
00121     if ((fd = open(src, O_RDONLY)) < 0)
00122         return 1;
00123 
00124     /* if((fd2 = open(dst, O_CREAT|O_TRUNC|O_WRONLY)) < 0) */
00125     if ((f2 = fopen(dst, "w")) == NULL) {
00126         close(fd);
00127         return 1;
00128     }
00129 
00130     fd2 = fileno(f2);
00131 
00132     while ((len = read(fd, buf, 1024)) > 0) {
00133         while (len && (len2 = write(fd2, buf, len)) >= 0)
00134             len -= len2;
00135     }
00136 
00137     close(fd);
00138     /* close(fd2); */
00139     fclose(f2);
00140 
00141     if (len == -1 || len2 == -1)
00142         return 1;
00143 
00144     return 0;
00145 }
00146 
00159 int
00160 Vect_copy(const char *in, const char *mapset, const char *out)
00161 {
00162     int i, n, ret, type;
00163     struct Map_info In, Out;
00164     struct field_info *Fi, *Fin;
00165     char old_path[GPATH_MAX], new_path[GPATH_MAX], buf[GPATH_MAX];
00166     struct stat info;
00167     const char *files[] = { GRASS_VECT_FRMT_ELEMENT, GRASS_VECT_COOR_ELEMENT,
00168         GRASS_VECT_HEAD_ELEMENT, GRASS_VECT_HIST_ELEMENT,
00169         GV_TOPO_ELEMENT, GV_SIDX_ELEMENT, GV_CIDX_ELEMENT,
00170         NULL
00171     };
00172     const char *xmapset;
00173 
00174     dbDriver *driver;
00175 
00176     G_debug(2, "Copy vector '%s' in '%s' to '%s'", in, mapset, out);
00177     /* check for [A-Za-z][A-Za-z0-9_]* in name */
00178     if (Vect_legal_filename(out) < 0)
00179         G_fatal_error(_("Vector map name is not SQL compliant"));
00180 
00181     xmapset = G_find_vector2(in, mapset);
00182     if (!xmapset) {
00183         G_warning(_("Unable to find vector map <%s> in <%s>"), in, mapset);
00184         return -1;
00185     }
00186     mapset = xmapset;
00187 
00188     /* Delete old vector if it exists */
00189     if (G_find_vector2(out, G_mapset())) {
00190         G_warning(_("Vector map <%s> already exists and will be overwritten"),
00191                   out);
00192         ret = Vect_delete(out);
00193         if (ret != 0) {
00194             G_warning(_("Unable to delete vector map <%s>"), out);
00195             return -1;
00196         }
00197     }
00198 
00199     /* Copy the directory */
00200     G__make_mapset_element(GRASS_VECT_DIRECTORY);
00201     sprintf(buf, "%s/%s", GRASS_VECT_DIRECTORY, out);
00202     G__make_mapset_element(buf);
00203 
00204     i = 0;
00205     while (files[i]) {
00206         sprintf(buf, "%s/%s", in, files[i]);
00207         G__file_name(old_path, GRASS_VECT_DIRECTORY, buf, mapset);
00208         sprintf(buf, "%s/%s", out, files[i]);
00209         G__file_name(new_path, GRASS_VECT_DIRECTORY, buf, G_mapset());
00210 
00211         if (stat(old_path, &info) == 0) {       /* file exists? */
00212             G_debug(2, "copy %s to %s", old_path, new_path);
00213             if (copy_file(old_path, new_path)) {
00214                 G_warning(_("Unable to copy vector map <%s> to <%s>"),
00215                           old_path, new_path);
00216             }
00217         }
00218         i++;
00219     }
00220 
00221     G__file_name(old_path, GRASS_VECT_DIRECTORY, in, mapset);
00222     G__file_name(new_path, GRASS_VECT_DIRECTORY, out, G_mapset());
00223 
00224     /* Open input */
00225     Vect_set_open_level(1);
00226     Vect_open_old_head(&In, in, mapset);
00227 
00228     if (In.format != GV_FORMAT_NATIVE) {        /* Done */
00229         Vect_close(&In);
00230         return 0;
00231     }
00232 
00233     /* Open output */
00234     Vect_open_update_head(&Out, out, G_mapset());
00235 
00236     /* Copy tables */
00237     n = Vect_get_num_dblinks(&In);
00238     type = GV_1TABLE;
00239     if (n > 1)
00240         type = GV_MTABLE;
00241     for (i = 0; i < n; i++) {
00242         Fi = Vect_get_dblink(&In, i);
00243         if (Fi == NULL) {
00244             G_warning(_("Database connection not defined for layer %d"),
00245                       In.dblnk->field[i].number);
00246             Vect_close(&In);
00247             Vect_close(&Out);
00248             return -1;
00249         }
00250         Fin = Vect_default_field_info(&Out, Fi->number, Fi->name, type);
00251         G_debug(3, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'",
00252                 Fi->driver, Fi->database, Fi->table, Fin->driver,
00253                 Fin->database, Fin->table);
00254         Vect_map_add_dblink(&Out, Fi->number, Fi->name, Fin->table, Fi->key,
00255                             Fin->database, Fin->driver);
00256 
00257         ret = db_copy_table(Fi->driver, Fi->database, Fi->table,
00258                             Fin->driver, Vect_subst_var(Fin->database, &Out),
00259                             Fin->table);
00260         if (ret == DB_FAILED) {
00261             G_warning(_("Unable to copy table <%s>"), Fin->table);
00262             Vect_close(&In);
00263             Vect_close(&Out);
00264             return -1;
00265         }
00266 
00267         driver =
00268             db_start_driver_open_database(Fin->driver,
00269                                           Vect_subst_var(Fin->database,
00270                                                          &Out));
00271         if (driver == NULL) {
00272             G_warning(_("Unable to open database <%s> by driver <%s>"),
00273                       Fin->database, Fin->driver);
00274         }
00275         else {
00276             if (db_create_index2(driver, Fin->table, Fi->key) != DB_OK)
00277                 G_warning(_("Unable to create index for table <%s>, key <%s>"),
00278                           Fi->table, Fi->key);
00279 
00280             db_close_database_shutdown_driver(driver);
00281         }
00282     }
00283 
00284     Vect_close(&In);
00285     Vect_close(&Out);
00286 
00287     return 0;
00288 }
00289 
00304 int Vect_rename(const char *in, const char *out)
00305 {
00306     int i, n, ret, type;
00307     struct Map_info Map;
00308     struct field_info *Fin, *Fout;
00309     int *fields;
00310     dbDriver *driver;
00311 
00312     G_debug(2, "Rename vector '%s' to '%s'", in, out);
00313     /* check for [A-Za-z][A-Za-z0-9_]* in name */
00314     if (Vect_legal_filename(out) < 0)
00315         G_fatal_error(_("Vector map name is not SQL compliant"));
00316 
00317     /* Delete old vector if it exists */
00318     if (G_find_vector2(out, G_mapset())) {
00319         G_warning(_("Vector map <%s> already exists and will be overwritten"),
00320                   out);
00321         Vect_delete(out);
00322     }
00323 
00324     /* Move the directory */
00325     ret = G_rename(GRASS_VECT_DIRECTORY, in, out);
00326 
00327     if (ret == 0) {
00328         G_warning(_("Vector map <%s> not found"), in);
00329         return -1;
00330     }
00331     else if (ret == -1) {
00332         G_warning(_("Unable to copy vector map <%s> to <%s>"), in, out);
00333         return -1;
00334     }
00335 
00336     /* Rename all tables if the format is native */
00337     Vect_set_open_level(1);
00338     Vect_open_update_head(&Map, out, G_mapset());
00339 
00340     if (Map.format != GV_FORMAT_NATIVE) {       /* Done */
00341         Vect_close(&Map);
00342         return 0;
00343     }
00344 
00345     /* Copy tables */
00346     n = Vect_get_num_dblinks(&Map);
00347     type = GV_1TABLE;
00348     if (n > 1)
00349         type = GV_MTABLE;
00350 
00351     /* Make the list of fields */
00352     fields = (int *)G_malloc(n * sizeof(int));
00353 
00354     for (i = 0; i < n; i++) {
00355         Fin = Vect_get_dblink(&Map, i);
00356 
00357         fields[i] = Fin->number;
00358     }
00359 
00360     for (i = 0; i < n; i++) {
00361         G_debug(3, "field[%d] = %d", i, fields[i]);
00362 
00363         Fin = Vect_get_field(&Map, fields[i]);
00364         if (Fin == NULL) {
00365             G_warning(_("Database connection not defined for layer %d"),
00366                       fields[i]);
00367             Vect_close(&Map);
00368             return -1;
00369         }
00370 
00371         Fout = Vect_default_field_info(&Map, Fin->number, Fin->name, type);
00372         G_debug(3, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'",
00373                 Fin->driver, Fin->database, Fin->table, Fout->driver,
00374                 Fout->database, Fout->table);
00375 
00376         /* TODO: db_rename_table instead of db_copy_table */
00377         ret = db_copy_table(Fin->driver, Fin->database, Fin->table,
00378                             Fout->driver, Vect_subst_var(Fout->database,
00379                                                          &Map), Fout->table);
00380 
00381         if (ret == DB_FAILED) {
00382             G_warning(_("Unable to copy table <%s>"), Fin->table);
00383             Vect_close(&Map);
00384             return -1;
00385         }
00386 
00387         /* Change the link */
00388         Vect_map_del_dblink(&Map, Fin->number);
00389 
00390         Vect_map_add_dblink(&Map, Fout->number, Fout->name, Fout->table,
00391                             Fin->key, Fout->database, Fout->driver);
00392 
00393         /* Delete old table */
00394         ret = db_delete_table(Fin->driver, Fin->database, Fin->table);
00395         if (ret == DB_FAILED) {
00396             G_warning(_("Unable to delete table <%s>"), Fin->table);
00397             Vect_close(&Map);
00398             return -1;
00399         }
00400 
00401         driver =
00402             db_start_driver_open_database(Fout->driver,
00403                                           Vect_subst_var(Fout->database,
00404                                                          &Map));
00405         if (driver == NULL) {
00406             G_warning(_("Unable to open database <%s> by driver <%s>"),
00407                       Fout->database, Fout->driver);
00408         }
00409         else {
00410             if (db_create_index2(driver, Fout->table, Fin->key) != DB_OK)
00411                 G_warning(_("Unable to create index for table <%s>, key <%s>"),
00412                           Fout->table, Fout->key);
00413 
00414             db_close_database_shutdown_driver(driver);
00415         }
00416     }
00417 
00418     Vect_close(&Map);
00419     free(fields);
00420 
00421     return 0;
00422 }
00423 
00432 int Vect_delete(const char *map)
00433 {
00434     int i, n, ret;
00435     struct Map_info Map;
00436     struct field_info *Fi;
00437     char buf[GPATH_MAX];
00438     DIR *dir;
00439     struct dirent *ent;
00440     const char *tmp;
00441 
00442     G_debug(3, "Delete vector '%s'", map);
00443 
00444     if (map == NULL || strlen(map) == 0) {
00445         G_warning(_("Invalid vector map name <%s>"), map ? map : "null");
00446         return -1;
00447     }
00448 
00449     sprintf(buf, "%s/%s/%s/%s/%s/%s", G_gisdbase(), G_location(),
00450             G_mapset(), GRASS_VECT_DIRECTORY, map, GRASS_VECT_DBLN_ELEMENT);
00451 
00452     G_debug(1, "dbln file: %s", buf);
00453 
00454     if (access(buf, F_OK) == 0) {
00455         /* Open input */
00456         Vect_set_open_level(1); /* Topo not needed */
00457         ret = Vect_open_old_head(&Map, map, G_mapset());
00458         if (ret < 1) {
00459             G_warning(_("Unable to open header file for vector map <%s>"),
00460                       map);
00461             return -1;
00462         }
00463 
00464         /* Delete all tables, NOT external (OGR) */
00465         if (Map.format == GV_FORMAT_NATIVE) {
00466 
00467             n = Vect_get_num_dblinks(&Map);
00468             for (i = 0; i < n; i++) {
00469                 Fi = Vect_get_dblink(&Map, i);
00470                 if (Fi == NULL) {
00471                     G_warning(_("Database connection not defined for layer %d"),
00472                               Map.dblnk->field[i].number);
00473                     Vect_close(&Map);
00474                     return -1;
00475                 }
00476                 G_debug(3, "Delete drv:db:table '%s:%s:%s'", Fi->driver,
00477                         Fi->database, Fi->table);
00478 
00479                 ret = db_table_exists(Fi->driver, Fi->database, Fi->table);
00480                 if (ret == -1) {
00481                     G_warning(_("Unable to find table <%s> linked to vector map <%s>"),
00482                               Fi->table, map);
00483                     Vect_close(&Map);
00484                     return -1;
00485                 }
00486 
00487                 if (ret == 1) {
00488                     ret =
00489                         db_delete_table(Fi->driver, Fi->database, Fi->table);
00490                     if (ret == DB_FAILED) {
00491                         G_warning(_("Unable to delete table <%s>"),
00492                                   Fi->table);
00493                         Vect_close(&Map);
00494                         return -1;
00495                     }
00496                 }
00497                 else {
00498                     G_warning(_("Table <%s> linked to vector map <%s> does not exist"),
00499                               Fi->table, map);
00500                 }
00501             }
00502         }
00503 
00504         Vect_close(&Map);
00505     }
00506 
00507     /* Delete all files from vector/name directory */
00508     sprintf(buf, "%s/%s/vector/%s", G_location_path(), G_mapset(), map);
00509     G_debug(3, "opendir '%s'", buf);
00510     dir = opendir(buf);
00511     if (dir == NULL) {
00512         G_warning(_("Unable to open directory '%s'"), buf);
00513         return -1;
00514     }
00515 
00516     while ((ent = readdir(dir))) {
00517         G_debug(3, "file = '%s'", ent->d_name);
00518         if ((strcmp(ent->d_name, ".") == 0) ||
00519             (strcmp(ent->d_name, "..") == 0))
00520             continue;
00521         sprintf(buf, "%s/%s/vector/%s/%s", G_location_path(), G_mapset(), map,
00522                 ent->d_name);
00523         G_debug(3, "delete file '%s'", buf);
00524         ret = remove(buf);
00525         if (ret == -1) {
00526             G_warning(_("Unable to delete file '%s'. Reason: %s"), buf, strerror(errno));
00527             closedir(dir);
00528             return -1;
00529         }
00530     }
00531     closedir(dir);
00532 
00533     /* NFS can create .nfsxxxxxxxx files for those deleted 
00534      *  -> we have to move the directory to ./tmp before it is deleted */
00535     sprintf(buf, "%s/%s/vector/%s", G_location_path(), G_mapset(), map);
00536 
00537     tmp = G_tempfile();
00538 
00539     G_debug(3, "rename '%s' to '%s'", buf, tmp);
00540     ret = rename(buf, tmp);
00541 
00542     if (ret == -1) {
00543         G_warning(_("Unable to rename directory '%s' to '%s'. Reason: %s"), buf, tmp, strerror(errno));
00544         return -1;
00545     }
00546 
00547     G_debug(3, "remove directory '%s'", tmp);
00548     /* Warning: remove() fails on Windows */
00549     ret = rmdir(tmp);
00550     if (ret == -1) {
00551         G_warning(_("Unable to remove directory '%s'. Reason: %s"), tmp, strerror(errno));
00552         return -1;
00553     }
00554 
00555     return 0;
00556 }
00557 
00572 int Vect_copy_tables(struct Map_info *In, struct Map_info *Out, int field)
00573 {
00574     int i, n, ret, type;
00575     struct field_info *Fi, *Fin;
00576     dbDriver *driver;
00577 
00578     n = Vect_get_num_dblinks(In);
00579 
00580     G_debug(2, "Vect_copy_tables(): copying %d tables",n);
00581 
00582     type = GV_1TABLE;
00583     if (n > 1)
00584         type = GV_MTABLE;
00585 
00586     for (i = 0; i < n; i++) {
00587         Fi = Vect_get_dblink(In, i);
00588         if (Fi == NULL) {
00589             G_warning(_("Database connection not defined for layer %d"),
00590                       In->dblnk->field[i].number);
00591             return -1;
00592         }
00593         if (field > 0 && Fi->number != field)
00594             continue;
00595 
00596         Fin = Vect_default_field_info(Out, Fi->number, Fi->name, type);
00597         G_debug(2, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'",
00598                 Fi->driver, Fi->database, Fi->table, Fin->driver,
00599                 Fin->database, Fin->table);
00600 
00601         ret =
00602             Vect_map_add_dblink(Out, Fi->number, Fi->name, Fin->table,
00603                                 Fi->key, Fin->database, Fin->driver);
00604         if (ret == -1) {
00605             G_warning(_("Unable to add database link for vector map <%s>"),
00606                       Out->name);
00607             return -1;
00608         }
00609 
00610         ret = db_copy_table(Fi->driver, Fi->database, Fi->table,
00611                             Fin->driver, Vect_subst_var(Fin->database, Out),
00612                             Fin->table);
00613         if (ret == DB_FAILED) {
00614             G_warning(_("Unable to copy table <%s>"), Fin->table);
00615             return -1;
00616         }
00617 
00618         driver =
00619             db_start_driver_open_database(Fin->driver,
00620                                           Vect_subst_var(Fin->database, Out));
00621         if (driver == NULL) {
00622             G_warning(_("Unable to open database <%s> by driver <%s>"),
00623                       Fin->database, Fin->driver);
00624         }
00625         else {
00626             if (db_create_index2(driver, Fin->table, Fi->key) != DB_OK)
00627                 G_warning(_("Unable to create index for table <%s>, key <%s>"),
00628                           Fin->table, Fin->key);
00629 
00630             db_close_database_shutdown_driver(driver);
00631         }
00632     }
00633 
00634     return 0;
00635 }
00636 
00650 int
00651 Vect_copy_table(struct Map_info *In, struct Map_info *Out, int field_in,
00652                 int field_out, const char *field_name, int type)
00653 {
00654     return Vect_copy_table_by_cats(In, Out, field_in, field_out, field_name,
00655                                    type, NULL, 0);
00656 }
00657 
00673 int
00674 Vect_copy_table_by_cats(struct Map_info *In, struct Map_info *Out,
00675                         int field_in, int field_out, const char *field_name,
00676                         int type, int *cats, int ncats)
00677 {
00678     int ret;
00679     struct field_info *Fi, *Fin;
00680     const char *name, *key;
00681 
00682     G_debug(2, "Vect_copy_table(): field_in = %d field_out = %d", field_in,
00683             field_out);
00684 
00685     Fi = Vect_get_field(In, field_in);
00686     if (Fi == NULL) {
00687         G_warning(_("Database connection not defined for layer %d"),
00688                   field_in);
00689         return -1;
00690     }
00691 
00692     if (field_name != NULL)
00693         name = field_name;
00694     else
00695         name = Fi->name;
00696 
00697     Fin = Vect_default_field_info(Out, field_out, name, type);
00698     G_debug(3, "Copy drv:db:table '%s:%s:%s' to '%s:%s:%s'",
00699             Fi->driver, Fi->database, Fi->table, Fin->driver, Fin->database,
00700             Fin->table);
00701 
00702     ret =
00703         Vect_map_add_dblink(Out, Fin->number, Fin->name, Fin->table, Fi->key,
00704                             Fin->database, Fin->driver);
00705     if (ret == -1) {
00706         G_warning(_("Unable to add database link for vector map <%s>"),
00707                   Out->name);
00708         return -1;
00709     }
00710 
00711     if (cats)
00712         key = Fi->key;
00713     else
00714         key = NULL;
00715 
00716     ret = db_copy_table_by_ints(Fi->driver, Fi->database, Fi->table,
00717                                 Fin->driver, Vect_subst_var(Fin->database,
00718                                                             Out), Fin->table,
00719                                 key, cats, ncats);
00720     if (ret == DB_FAILED) {
00721         G_warning(_("Unable to copy table <%s>"), Fin->table);
00722         return -1;
00723     }
00724 
00725     return 0;
00726 }
00727 
00737 void Vect_set_release_support(struct Map_info *Map)
00738 {
00739     Map->plus.release_support = 1;
00740 }
00741 
00752 void Vect_set_category_index_update(struct Map_info *Map)
00753 {
00754     Map->plus.update_cidx = 1;
00755 }