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