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