GRASS Programmer's Manual  6.5.svn(2012)-r51648
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines
closecell.c
Go to the documentation of this file.
00001 /***********************************************************************
00002  *
00003  *   G_close_cell(fd)
00004  *      Closes and does housekeeping on an opened cell file
00005  *
00006  *   G_unopen_cell(fd)
00007  *      Closes and does housekeeping on an opened cell file
00008  *      without creating the cell file
00009  *
00010  *   parms:
00011  *      int fd     open cell file
00012  *
00013  *   returns:
00014  *      -1   on fail
00015  *       0   on success
00016  *
00017  *   note:
00018  *      On closing of a cell file that was open for writing, dummy cats
00019  *      and history files are created. Histogram and range info are written.
00020  *
00021  **********************************************************************/
00022 
00023 #ifdef __MINGW32__
00024 #  include <windows.h>
00025 #endif
00026 
00027 #include <stdio.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <unistd.h>
00031 #include <errno.h>
00032 #include <fcntl.h>
00033 #include <signal.h>
00034 #include <grass/gis.h>
00035 #include <grass/glocale.h>
00036 #include "G.h"
00037 
00038 #define FORMAT_FILE "f_format"
00039 #define QUANT_FILE  "f_quant"
00040 #define NULL_FILE   "null"
00041 
00042 static int close_old(int);
00043 static int close_new(int, int);
00044 static char CELL_DIR[100];
00045 
00046 
00072 int G_close_cell(int fd)
00073 {
00074     struct fileinfo *fcb = &G__.fileinfo[fd];
00075 
00076     if (fd < 0 || fd >= G__.fileinfo_count || fcb->open_mode <= 0)
00077         return -1;
00078     if (fcb->open_mode == OPEN_OLD)
00079         return close_old(fd);
00080 
00081     return close_new(fd, 1);
00082 }
00083 
00084 
00105 int G_unopen_cell(int fd)
00106 {
00107     struct fileinfo *fcb = &G__.fileinfo[fd];
00108 
00109     G_debug(5, "G_unopen_cell()");
00110     if (fd < 0 || fd >= G__.fileinfo_count || fcb->open_mode <= 0)
00111         return -1;
00112     if (fcb->open_mode == OPEN_OLD)
00113         return close_old(fd);
00114     else
00115         return close_new(fd, 0);
00116 }
00117 
00118 static int close_old(int fd)
00119 {
00120     struct fileinfo *fcb = &G__.fileinfo[fd];
00121     int i;
00122 
00123     /* if G__.auto_mask was only allocated for reading map rows to create
00124        non-existant null rows, and not for actuall mask, free G__.mask_row 
00125        if(G__.auto_mask <=0)
00126        G_free (G__.mask_buf);
00127        This is obsolete since now the mask_bus is always allocated
00128      */
00129 
00130     if (fcb->gdal)
00131         G_close_gdal_link(fcb->gdal);
00132 
00133     for (i = 0; i < NULL_ROWS_INMEM; i++)
00134         G_free(fcb->NULL_ROWS[i]);
00135     G_free(fcb->null_work_buf);
00136 
00137     if (fcb->cellhd.compressed)
00138         G_free(fcb->row_ptr);
00139     G_free(fcb->col_map);
00140     G_free(fcb->mapset);
00141     G_free(fcb->data);
00142     G_free(fcb->name);
00143     if (fcb->reclass_flag)
00144         G_free_reclass(&fcb->reclass);
00145     fcb->open_mode = -1;
00146 
00147     if (fcb->map_type != CELL_TYPE) {
00148         G_quant_free(&fcb->quant);
00149         xdr_destroy(&fcb->xdrstream);
00150     }
00151     close(fd);
00152 
00153     return 1;
00154 }
00155 
00156 static int close_new(int fd, int ok)
00157 {
00158     struct fileinfo *fcb = &G__.fileinfo[fd];
00159     int stat;
00160     struct Categories cats;
00161     struct History hist;
00162     char path[GPATH_MAX];
00163     CELL cell_min, cell_max;
00164     int row, i, open_mode;
00165 
00166     if (ok) {
00167         switch (fcb->open_mode) {
00168         case OPEN_NEW_COMPRESSED:
00169             G_debug(1, "close %s compressed", fcb->name);
00170             break;
00171         case OPEN_NEW_UNCOMPRESSED:
00172             G_debug(1, "close %s uncompressed", fcb->name);
00173             break;
00174         case OPEN_NEW_RANDOM:
00175             G_debug(1, "close %s random", fcb->name);
00176             break;
00177         }
00178 
00179         if (fcb->open_mode != OPEN_NEW_RANDOM &&
00180             fcb->cur_row < fcb->cellhd.rows) {
00181             G_zero_raster_buf(fcb->data, fcb->map_type);
00182             for (row = fcb->cur_row; row < fcb->cellhd.rows; row++)
00183                 G_put_raster_row(fd, fcb->data, fcb->map_type);
00184             G_free(fcb->data);
00185             fcb->data = NULL;
00186         }
00187 
00188         /* create path : full null file name */
00189         G__make_mapset_element_misc("cell_misc", fcb->name);
00190         G__file_name_misc(path, "cell_misc", NULL_FILE, fcb->name,
00191                           G_mapset());
00192 
00193         if (access(path, F_OK) == 0) {
00194             if (remove(path) != 0) {
00195                 perror(path);
00196                 G_warning(_("Unable to delete prior null-cells file"));
00197             }
00198         }
00199 
00200         if (fcb->null_cur_row > 0) {
00201             /* if temporary NULL file exists, write it into cell_misc/name/null */
00202             int null_fd;
00203 
00204             null_fd = G__open_null_write(fd);
00205             if (null_fd <= 0)
00206                 return -1;
00207             if (null_fd < 1)
00208                 return -1;
00209 
00210             /* first finish writing null file */
00211             /* write out the rows stored in memory */
00212             for (row = fcb->min_null_row; row < fcb->null_cur_row; row++)
00213                 G__write_null_bits(null_fd,
00214                                    fcb->NULL_ROWS[row - fcb->min_null_row],
00215                                    row, fcb->cellhd.cols, fd);
00216 
00217             /* write missing rows */
00218             if (fcb->open_mode != OPEN_NEW_RANDOM
00219                 && fcb->null_cur_row < fcb->cellhd.rows) {
00220                 G__init_null_bits(fcb->null_work_buf, fcb->cellhd.cols);
00221                 for (row = fcb->null_cur_row; row < fcb->cellhd.rows; row++)
00222                     G__write_null_bits(null_fd, fcb->null_work_buf, row,
00223                                        fcb->cellhd.cols, fd);
00224             }
00225             if (close(null_fd) != 0)
00226                 G_warning(_("Unable to close the null-cells file"));
00227 
00228             if (rename(fcb->null_temp_name, path)) {
00229                 G_warning(_("closecell: can't move [%s] to null-cells file [%s]"),
00230                           fcb->null_temp_name, path);
00231                 stat = -1;
00232             }
00233             else { /* if the rename() was successful I'm not sure why there'd be anything left to remove() */
00234                 if (access(fcb->null_temp_name, F_OK) == 0) {
00235                     if (remove(fcb->null_temp_name) != 0)
00236                         G_warning(_("Unable to delete the temporary null-cells file"));
00237                 }
00238             }
00239         }
00240         else { /* no NULL data encountered */
00241             if (access(fcb->null_temp_name, F_OK) == 0) {
00242                 if (remove(fcb->null_temp_name) != 0)
00243                     G_warning(_("Unable to delete the empty temporary null-cells file"));
00244             }
00245             if (access(path, F_OK) == 0) {
00246                 if (remove(path) != 0)  /* duplicate? */
00247                     G_warning(_("Unable to delete the prior null-cells file"));
00248             }
00249         }               /* null_cur_row > 0 */
00250 
00251 
00252         if (fcb->open_mode == OPEN_NEW_COMPRESSED) {    /* auto compression */
00253             fcb->row_ptr[fcb->cellhd.rows] = lseek(fd, 0L, SEEK_CUR);
00254             G__write_row_ptrs(fd);
00255         }
00256 
00257         if (fcb->map_type != CELL_TYPE) {       /* floating point map */
00258             int cell_fd;
00259 
00260             if (G__write_fp_format(fd) != 0) {
00261                 G_warning(_("Error writing floating point format file for map %s"),
00262                           fcb->name);
00263                 stat = -1;
00264             }
00265 
00266             /* now write 0-length cell file */
00267             G__make_mapset_element("cell");
00268             cell_fd =
00269                 creat(G__file_name(path, "cell", fcb->name, fcb->mapset),
00270                       0666);
00271             if (close(cell_fd) != 0)
00272                 G_warning(_("Unable to close the 'cell' file"));
00273 
00274             strcpy(CELL_DIR, "fcell");
00275         }
00276         else {
00277             /* it's a CELL map, so remove fcell/name file if it exists */
00278             G__file_name(path, "fcell", fcb->name, fcb->mapset);
00279 
00280             if (access(path, F_OK) == 0) {
00281                 if (remove(path) != 0)
00282                     G_warning(_("Unable to delete prior 'fcell' file"));
00283             }
00284 
00285             /* remove cell_misc/name/f_format */
00286             G__file_name_misc(path, "cell_misc", FORMAT_FILE, fcb->name,
00287                               fcb->mapset);
00288 
00289             if (access(path, F_OK) == 0) {
00290                 if (remove(path) != 0)
00291                     G_warning(_("Unable to delete the prior %s file"), FORMAT_FILE);
00292             }
00293 
00294             strcpy(CELL_DIR, "cell");
00295         }
00296     }           /* if(ok) */
00297 
00298     /* NOW CLOSE THE FILE DESCRIPTOR */
00299     if (close(fd) != 0)
00300         G_warning(_("Unable to close file"));
00301 
00302     /* remember open_mode */
00303     open_mode = fcb->open_mode;
00304     fcb->open_mode = -1;
00305 
00306     if (fcb->data != NULL)
00307         G_free(fcb->data);
00308 
00309     if (fcb->null_temp_name != NULL) {
00310         G_free(fcb->null_temp_name);
00311         fcb->null_temp_name = NULL;
00312     }
00313 
00314     /* if the cell file was written to a temporary file
00315      * move this temporary file into the cell file
00316      * if the move fails, tell the user, but go ahead and create
00317      * the support files
00318      */
00319     stat = 1;
00320     if (ok && (fcb->temp_name != NULL)) {
00321         G_debug(5, "Moving temporary cell map into main mapset...");
00322         G__file_name(path, CELL_DIR, fcb->name, fcb->mapset);
00323 
00324         if (access(path, F_OK) == 0) {
00325             if (remove(path) != 0) {
00326                 perror(path);
00327                 G_warning(_("Unable to delete the prior 'cell' file"));
00328             }
00329         }
00330 
00331         if (rename(fcb->temp_name, path)) {
00332             G_warning(_("closecell: can't move [%s] to cell file [%s]"),
00333                       fcb->temp_name, path);
00334             stat = -1;
00335         }
00336         else { /* if the rename() was successful I'm not sure why there'd be anything left to remove() */
00337             if (access(fcb->temp_name, F_OK) == 0) {
00338                 if (remove(fcb->temp_name) != 0)
00339                     G_warning(_("Unable to delete the temporary 'cell' file"));
00340             }
00341         }
00342     }
00343 
00344     if (fcb->temp_name != NULL) {
00345         G_free(fcb->temp_name);
00346     }
00347 
00348     if (ok) {
00349         /* remove color table */
00350         G_remove_colors(fcb->name, "");
00351 
00352         /* create a history file */
00353         G_short_history(fcb->name, "raster", &hist);
00354         G_write_history(fcb->name, &hist);
00355 
00356         /* write the range */
00357         if (fcb->map_type == CELL_TYPE) {
00358             G_write_range(fcb->name, &fcb->range);
00359             G__remove_fp_range(fcb->name);
00360         }
00361         /*NOTE: int range for floating point maps is not written out */
00362         else {                  /* if(fcb->map_type != CELL_TYPE) */
00363 
00364             G_write_fp_range(fcb->name, &fcb->fp_range);
00365             G_construct_default_range(&fcb->range);
00366             /* this range will be used to add default rule to quant structure */
00367         }
00368 
00369         if (fcb->map_type != CELL_TYPE)
00370             fcb->cellhd.format = -1;
00371         else                    /* CELL map */
00372             fcb->cellhd.format = fcb->nbytes - 1;
00373 
00374         /* write header file */
00375         G_put_cellhd(fcb->name, &fcb->cellhd);
00376 
00377         /* if map is floating point write the quant rules, otherwise remove f_quant */
00378         if (fcb->map_type != CELL_TYPE) {
00379             /* DEFAULT RANGE QUANT
00380                G_get_fp_range_min_max(&fcb->fp_range, &dcell_min, &dcell_max);
00381                if(!G_is_d_null_value(&dcell_min) && !G_is_d_null_value(&dcell_max))
00382                {
00383                G_get_range_min_max(&fcb->range, &cell_min, &cell_max);
00384                G_quant_add_rule(&fcb->quant, dcell_min, dcell_max, 
00385                cell_min, cell_max);
00386                }
00387              */
00388             G_quant_round(&fcb->quant);
00389             if (G_write_quant(fcb->name, fcb->mapset, &fcb->quant) < 0)
00390                 G_warning(_("Unable to write quant file!"));
00391         }
00392         else {
00393             /* remove cell_misc/name/f_quant */
00394             G__file_name_misc(path, "cell_misc", QUANT_FILE, fcb->name,
00395                               fcb->mapset);
00396             if (access(path, F_OK) == 0) {
00397                 if (remove(path) != 0)
00398                     G_warning(_("Unable to delete the %s file"), QUANT_FILE);
00399             }
00400         }
00401 
00402         /* create empty cats file */
00403         G_get_range_min_max(&fcb->range, &cell_min, &cell_max);
00404         if (G_is_c_null_value(&cell_max))
00405             cell_max = 0;
00406         G_init_cats(cell_max, (char *)NULL, &cats);
00407         G_write_cats(fcb->name, &cats);
00408         G_free_cats(&cats);
00409 
00410         /* write the histogram */
00411         /* only works for integer maps */
00412         if ((fcb->map_type == CELL_TYPE)
00413             && (fcb->want_histogram)) {
00414             G_write_histogram_cs(fcb->name, &fcb->statf);
00415             G_free_cell_stats(&fcb->statf);
00416         }
00417         else {
00418             G_remove_histogram(fcb->name);
00419         }
00420     }                           /* OK */
00421 
00422     G_free(fcb->name);
00423     G_free(fcb->mapset);
00424 
00425     for (i = 0; i < NULL_ROWS_INMEM; i++)
00426         G_free(fcb->NULL_ROWS[i]);
00427     G_free(fcb->null_work_buf);
00428 
00429     if (fcb->map_type != CELL_TYPE)
00430         G_quant_free(&fcb->quant);
00431 
00432     return stat;
00433 }
00434 
00435 /* returns 0 on success, 1 on failure */
00436 int G__write_fp_format(int fd)
00437 {
00438     struct fileinfo *fcb = &G__.fileinfo[fd];
00439     struct Key_Value *format_kv;
00440     char path[GPATH_MAX];
00441     int stat;
00442 
00443     if (fcb->map_type == CELL_TYPE) {
00444         G_warning(_("Unable to write f_format file for CELL maps"));
00445         return 0;
00446     }
00447     format_kv = G_create_key_value();
00448     if (fcb->map_type == FCELL_TYPE)
00449         G_set_key_value("type", "float", format_kv);
00450     else
00451         G_set_key_value("type", "double", format_kv);
00452 
00453     G_set_key_value("byte_order", "xdr", format_kv);
00454 
00455     if (fcb->open_mode == OPEN_NEW_COMPRESSED)
00456         G_set_key_value("lzw_compression_bits", "-1", format_kv);
00457 
00458     G__make_mapset_element_misc("cell_misc", fcb->name);
00459     G__file_name_misc(path, "cell_misc", FORMAT_FILE, fcb->name, fcb->mapset);
00460     G_write_key_value_file(path, format_kv, &stat);
00461 
00462     G_free_key_value(format_kv);
00463 
00464     return stat;
00465 }