file.c 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. /*!
  2. \file diglib/file.c
  3. \brief Vector library - file management (lower level functions)
  4. Lower level functions for reading/writing/manipulating vectors.
  5. Note: seems that the time is almost the same for both cases:
  6. - reading from file
  7. - load whole file to memory and read from memory
  8. (C) 2001-2009 by the GRASS Development Team
  9. This program is free software under the GNU General Public License
  10. (>=v2). Read the file COPYING that comes with GRASS for details.
  11. \author Original author CERL, probably Dave Gerdes
  12. \author Update to GRASS 5.7 Radim Blazek
  13. */
  14. #include <grass/config.h>
  15. #include <string.h>
  16. #include <stdio.h>
  17. #include <unistd.h>
  18. #include <sys/types.h>
  19. #include <sys/stat.h>
  20. #include <grass/gis.h>
  21. #include <grass/vector.h>
  22. #include <grass/glocale.h>
  23. /*!
  24. \brief Get struct gvfile position.
  25. \param file pointer to struct gvfile structure
  26. \return current file position
  27. */
  28. off_t dig_ftell(struct gvfile *file)
  29. {
  30. if (file->loaded) /* using memory */
  31. return (file->current - file->start);
  32. return (G_ftell(file->file));
  33. }
  34. /*!
  35. \brief Set struct gvfile position.
  36. Start positions:
  37. - SEEK_SET (start)
  38. - SEEK_CUR (current position)
  39. - SEEK_END (end)
  40. \param file pointer to struct gvfile structure
  41. \param offset offset position
  42. \param whence start position
  43. \return 0 OK
  44. \return -1 error
  45. */
  46. int dig_fseek(struct gvfile * file, off_t offset, int whence)
  47. {
  48. if (file->loaded) { /* using memory */
  49. switch (whence) {
  50. case SEEK_SET:
  51. file->current = file->start + offset;
  52. break;
  53. case SEEK_CUR:
  54. file->current += offset;
  55. break;
  56. case SEEK_END:
  57. file->current = file->start + file->size + offset;
  58. break;
  59. }
  60. return 0;
  61. }
  62. G_fseek(file->file, offset, whence);
  63. return 0;
  64. }
  65. /*!
  66. \brief Rewind file position.
  67. \param file pointer to gvfile structure
  68. */
  69. void dig_rewind(struct gvfile * file)
  70. {
  71. if (file->loaded) { /* using memory */
  72. file->current = file->start;
  73. }
  74. else {
  75. rewind(file->file);
  76. }
  77. }
  78. /*!
  79. \brief Flush struct gvfile.
  80. \param file pointer to struct gvfile structure
  81. \return 0
  82. */
  83. int dig_fflush(struct gvfile * file)
  84. {
  85. if (file->loaded) { /* using memory */
  86. return 0;
  87. }
  88. else {
  89. return (fflush(file->file));
  90. }
  91. }
  92. /*!
  93. \brief Read struct gvfile.
  94. \param[out] ptr data buffer
  95. \param size buffer size
  96. \param nmemb number of members
  97. \param file pointer to struct gvfile structure
  98. \return number of read members
  99. */
  100. size_t dig_fread(void *ptr, size_t size, size_t nmemb, struct gvfile *file)
  101. {
  102. long tot;
  103. size_t cnt;
  104. if (file->loaded) { /* using memory */
  105. if (file->current >= file->end) { /* EOF */
  106. return 0;
  107. }
  108. tot = size * nmemb;
  109. cnt = nmemb;
  110. if (file->current + tot > file->end) {
  111. tot = file->end - file->current;
  112. cnt = (int)tot / size;
  113. }
  114. memcpy(ptr, file->current, tot);
  115. file->current += tot;
  116. return (cnt);
  117. }
  118. return (fread(ptr, size, nmemb, file->file));
  119. }
  120. /*!
  121. \brief Write struct gvfile.
  122. \param ptr data buffer
  123. \param size buffer size
  124. \param nmemb number of members
  125. \param[out] file pointer to struct gvfile structure
  126. \return number of items written
  127. */
  128. size_t dig_fwrite(const void *ptr, size_t size, size_t nmemb, struct gvfile *file)
  129. {
  130. if (file->loaded) { /* using memory */
  131. G_fatal_error(_("Writing to file loaded to memory not supported"));
  132. }
  133. return fwrite(ptr, size, nmemb, file->file);
  134. }
  135. /*!
  136. \brief Initialize gvfile strcuture
  137. \param[in,out] file pointer to gvfile structure
  138. */
  139. void dig_file_init(struct gvfile *file)
  140. {
  141. file->file = NULL;
  142. file->start = NULL;
  143. file->current = NULL;
  144. file->end = NULL;
  145. file->size = 0;
  146. file->alloc = 0;
  147. file->loaded = 0;
  148. }
  149. /*!
  150. \brief Load opened struct gvfile to memory.
  151. Warning: position in file is set to the beginning.
  152. \param file pointer to struct gvfile structure
  153. \return 1 loaded
  154. \return 0 not loaded
  155. \return -1 error
  156. */
  157. int dig_file_load(struct gvfile * file)
  158. {
  159. int ret, mode, load;
  160. const char *cmode;
  161. size_t size;
  162. struct stat sbuf;
  163. G_debug(2, "dig_file_load ()");
  164. if (file->file == NULL) {
  165. G_warning(_("Unable to load file to memory, file not open"));
  166. return -1;
  167. }
  168. /* Get mode */
  169. mode = GV_MEMORY_NEVER;
  170. cmode = G__getenv("GV_MEMORY");
  171. if (cmode != NULL) {
  172. if (G_strcasecmp(cmode, "ALWAYS") == 0)
  173. mode = GV_MEMORY_ALWAYS;
  174. else if (G_strcasecmp(cmode, "NEVER") == 0)
  175. mode = GV_MEMORY_NEVER;
  176. else if (G_strcasecmp(cmode, "AUTO") == 0)
  177. mode = GV_MEMORY_AUTO;
  178. else
  179. G_warning(_("Vector memory mode not supported, using 'AUTO'"));
  180. }
  181. G_debug(2, " requested mode = %d", mode);
  182. fstat(fileno(file->file), &sbuf);
  183. size = sbuf.st_size;
  184. G_debug(2, " size = %lu", (long unsigned int) size);
  185. /* Decide if the file should be loaded */
  186. /* TODO: I don't know how to get size of free memory (portability) to decide if load or not for auto */
  187. if (mode == GV_MEMORY_AUTO)
  188. mode = GV_MEMORY_NEVER;
  189. if (mode == GV_MEMORY_ALWAYS)
  190. load = 1;
  191. else
  192. load = 0;
  193. if (load) {
  194. file->start = G_malloc(size);
  195. if (file->start == NULL)
  196. return -1;
  197. fseek(file->file, 0L, 0);
  198. ret = fread(file->start, size, 1, file->file); /* Better to read in smaller portions? */
  199. fseek(file->file, 0L, 0); /* reset to the beginning */
  200. if (ret <= 0) {
  201. G_free(file->start);
  202. return -1;
  203. }
  204. file->alloc = size;
  205. file->size = size;
  206. file->current = file->start;
  207. file->end = file->start + size;
  208. file->loaded = 1;
  209. G_debug(2, " file was loaded to the memory");
  210. return 1;
  211. }
  212. else {
  213. G_debug(2, " file was not loaded to the memory");
  214. }
  215. return 0;
  216. }
  217. /*!
  218. \brief Free struct gvfile.
  219. \param file pointer to struct gvfile structure
  220. */
  221. void dig_file_free(struct gvfile * file)
  222. {
  223. if (file->loaded) {
  224. G_free(file->start);
  225. file->loaded = 0;
  226. file->alloc = 0;
  227. }
  228. }