/*! \file diglib/file.c \brief Vector library - file management (lower level functions) Lower level functions for reading/writing/manipulating vectors. Note: seems that the time is almost the same for both cases: - reading from file - load whole file to memory and read from memory (C) 2001-2009 by the GRASS Development Team This program is free software under the GNU General Public License (>=v2). Read the file COPYING that comes with GRASS for details. \author Original author CERL, probably Dave Gerdes \author Update to GRASS 5.7 Radim Blazek */ #include #include #include #include #include #include #include /*! \brief Get struct gvfile position. \param file pointer to struct gvfile structure \return current file position */ off_t dig_ftell(struct gvfile *file) { if (file->loaded) /* using memory */ return (file->current - file->start); return (G_ftell(file->file)); } /*! \brief Set struct gvfile position. Start positions: - SEEK_SET (start) - SEEK_CUR (current position) - SEEK_END (end) \param file pointer to struct gvfile structure \param offset offset position \param whence start position \return 0 OK \return -1 error */ int dig_fseek(struct gvfile * file, off_t offset, int whence) { if (file->loaded) { /* using memory */ switch (whence) { case SEEK_SET: file->current = file->start + offset; break; case SEEK_CUR: file->current += offset; break; case SEEK_END: file->current = file->start + file->size + offset; break; } return 0; } G_fseek(file->file, offset, whence); return 0; } /*! \brief Rewind file position. \param file pointer to gvfile structure */ void dig_rewind(struct gvfile * file) { if (file->loaded) { /* using memory */ file->current = file->start; } else { rewind(file->file); } } /*! \brief Flush struct gvfile. \param file pointer to struct gvfile structure \return 0 */ int dig_fflush(struct gvfile * file) { if (file->loaded) { /* using memory */ return 0; } else { return (fflush(file->file)); } } /*! \brief Read struct gvfile. \param[out] ptr data buffer \param size buffer size \param nmemb number of members \param file pointer to struct gvfile structure \return number of read members */ size_t dig_fread(void *ptr, size_t size, size_t nmemb, struct gvfile *file) { long tot; size_t cnt; if (file->loaded) { /* using memory */ if (file->current >= file->end) { /* EOF */ return 0; } tot = size * nmemb; cnt = nmemb; if (file->current + tot > file->end) { tot = file->end - file->current; cnt = (int)tot / size; } memcpy(ptr, file->current, tot); file->current += tot; return (cnt); } return (fread(ptr, size, nmemb, file->file)); } /*! \brief Write struct gvfile. \param ptr data buffer \param size buffer size \param nmemb number of members \param[out] file pointer to struct gvfile structure \return number of items written */ size_t dig_fwrite(const void *ptr, size_t size, size_t nmemb, struct gvfile *file) { if (file->loaded) { /* using memory */ G_fatal_error(_("Writing to file loaded to memory not supported")); } return fwrite(ptr, size, nmemb, file->file); } /*! \brief Initialize gvfile strcuture \param[in,out] file pointer to gvfile structure */ void dig_file_init(struct gvfile *file) { G_zero(file, sizeof(struct gvfile)); } /*! \brief Load opened struct gvfile to memory. Warning: position in file is set to the beginning. \param file pointer to struct gvfile structure \return 1 loaded \return 0 not loaded \return -1 error */ /* unused, coor file is never loaded to memory. Remove ? MM 2010 */ int dig_file_load(struct gvfile * file) { int ret, mode, load; const char *cmode; size_t size; struct stat sbuf; G_debug(2, "dig_file_load ()"); if (file->file == NULL) { G_warning(_("Unable to load file to memory, file not open")); return -1; } /* Get mode */ mode = GV_MEMORY_NEVER; cmode = G_getenv_nofatal("GV_MEMORY"); if (cmode != NULL) { if (G_strcasecmp(cmode, "ALWAYS") == 0) mode = GV_MEMORY_ALWAYS; else if (G_strcasecmp(cmode, "NEVER") == 0) mode = GV_MEMORY_NEVER; else if (G_strcasecmp(cmode, "AUTO") == 0) mode = GV_MEMORY_AUTO; else G_warning(_("Vector memory mode not supported, using 'AUTO'")); } G_debug(2, " requested mode = %d", mode); fstat(fileno(file->file), &sbuf); size = sbuf.st_size; G_debug(2, " size = %lu", (long unsigned int) size); /* Decide if the file should be loaded */ /* TODO: I don't know how to get size of free memory (portability) to decide if load or not for auto */ if (mode == GV_MEMORY_AUTO) mode = GV_MEMORY_NEVER; if (mode == GV_MEMORY_ALWAYS) load = 1; else load = 0; if (load) { file->start = G_malloc(size); if (file->start == NULL) return -1; G_fseek(file->file, 0L, 0); ret = fread(file->start, size, 1, file->file); /* Better to read in smaller portions? */ G_fseek(file->file, 0L, 0); /* reset to the beginning */ if (ret <= 0) { G_free(file->start); return -1; } file->alloc = size; file->size = size; file->current = file->start; file->end = file->start + size; file->loaded = 1; G_debug(2, " file was loaded to the memory"); return 1; } else { G_debug(2, " file was not loaded to the memory"); } return 0; } /*! \brief Free struct gvfile. \param file pointer to struct gvfile structure */ void dig_file_free(struct gvfile * file) { if (file->loaded) { G_free(file->start); file->loaded = 0; file->alloc = 0; } }