Added function gerb_filenames_in_zip() to find files in zip.
[geda-gerbv/spe.git] / src / gerb_file.c
blobd9f74a11ca7b525c2d4fed0ac0ae7d7c2625e9c9
1 /*
2 * gEDA - GNU Electronic Design Automation
3 * This file is a part of gerbv.
5 * Copyright (C) 2000-2002 Stefan Petersen (spe@stacken.kth.se)
7 * $Id$
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA
24 /** \file gerb_file.c
25 \brief File parsing support functions
26 \ingroup libgerbv
29 #ifdef HAVE_CONFIG_H
30 #include "config.h"
31 #endif
33 #include <stdlib.h>
34 #include <stdio.h>
35 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #ifdef HAVE_UNISTD_H
40 #include <unistd.h>
41 #endif
42 #ifdef HAVE_SYS_MMAN_H
43 #include <sys/mman.h>
44 #endif
45 #include <errno.h>
47 #include "common.h"
48 #include "unzip/unzip.h"
49 #include "gerbv.h"
50 #include "gerb_file.h"
52 #define GERB_FILE_ZFILENAME_LEN_MAX 255
54 /* DEBUG printing. #define DEBUG 1 in config.h to use this fcn. */
55 #define dprintf if(DEBUG) printf
57 gerb_file_t *
58 gerb_fopen(char const * filename)
60 gerb_file_t *fd;
61 struct stat statinfo;
63 dprintf("---> Entering gerb_fopen, filename = %s\n", filename);
64 #ifdef HAVE_SYS_MMAN_H
65 fd = (gerb_file_t *)g_malloc(sizeof(gerb_file_t));
66 if (fd == NULL) {
67 return NULL;
70 dprintf(" Doing fopen\n");
71 fd->fd = fopen(filename, "r");
72 if (fd->fd == NULL) {
73 g_free(fd);
74 return NULL;
77 dprintf(" Doing fstat\n");
78 fd->ptr = 0;
79 fd->fileno = fileno(fd->fd);
80 if (fstat(fd->fileno, &statinfo) < 0) {
81 fclose(fd->fd);
82 g_free(fd);
83 return NULL;
86 dprintf(" Checking S_ISREG\n");
87 if (!S_ISREG(statinfo.st_mode)) {
88 fclose(fd->fd);
89 g_free(fd);
90 errno = EISDIR;
91 return NULL;
94 dprintf(" Checking statinfo.st_size\n");
95 if ((int)statinfo.st_size == 0) {
96 fclose(fd->fd);
97 g_free(fd);
98 errno = EIO; /* More compatible with the world outside Linux */
99 return NULL;
102 dprintf(" Doing mmap\n");
103 fd->datalen = (int)statinfo.st_size;
104 fd->data = (char *)mmap(0, statinfo.st_size, PROT_READ, MAP_PRIVATE,
105 fd->fileno, 0);
106 if(fd->data == MAP_FAILED) {
107 fclose(fd->fd);
108 g_free(fd);
109 fd = NULL;
111 #else
112 /* all systems without mmap, not only MINGW32 */
113 fd = (gerb_file_t *)g_malloc(sizeof(gerb_file_t));
114 if (fd == NULL) {
115 return NULL;
118 if (stat(filename, &statinfo) < 0) {
119 fclose(fd->fd);
120 g_free(fd);
121 return NULL;
124 fd->fd = fopen(filename, "rb");
125 fd->ptr = 0;
126 fd->fileno = fileno(fd->fd);
127 if (fstat(fd->fileno, &statinfo) < 0) {
128 fclose(fd->fd);
129 g_free(fd);
130 return NULL;
132 if (!S_ISREG(statinfo.st_mode)) {
133 fclose(fd->fd);
134 g_free(fd);
135 errno = EISDIR;
136 return NULL;
138 if ((int)statinfo.st_size == 0) {
139 fclose(fd->fd);
140 g_free(fd);
141 errno = EIO; /* More compatible with the world outside Linux */
142 return NULL;
144 fd->datalen = (int)statinfo.st_size;
145 fd->data = calloc(1, statinfo.st_size + 1);
146 if (fd->data == NULL) {
147 fclose(fd->fd);
148 g_free(fd);
149 return NULL;
151 if (fread((void*)fd->data, 1, statinfo.st_size, fd->fd) != statinfo.st_size) {
152 fclose(fd->fd);
153 g_free(fd->data);
154 g_free(fd);
155 return NULL;
157 rewind (fd->fd);
158 #endif
160 dprintf("<--- Leaving gerb_fopen\n");
161 return fd;
162 } /* gerb_fopen */
166 gerb_fgetc(gerb_file_t *fd)
169 if (fd->ptr >= fd->datalen)
170 return EOF;
172 return (int) fd->data[fd->ptr++];
173 } /* gerb_fgetc */
177 gerb_fgetint(gerb_file_t *fd, int *len)
179 long int result;
180 char *end;
182 errno = 0;
183 result = strtol(fd->data + fd->ptr, &end, 10);
184 if (errno) {
185 GERB_COMPILE_ERROR("Failed to read integer");
186 return 0;
189 if (len) {
190 *len = end - (fd->data + fd->ptr);
193 fd->ptr = end - fd->data;
195 if (len && (result < 0))
196 *len -= 1;
198 return (int)result;
199 } /* gerb_fgetint */
202 double
203 gerb_fgetdouble(gerb_file_t *fd)
205 double result;
206 char *end;
208 errno = 0;
209 result = strtod(fd->data + fd->ptr, &end);
210 if (errno) {
211 GERB_COMPILE_ERROR("Failed to read double");
212 return 0.0;
215 fd->ptr = end - fd->data;
217 return result;
218 } /* gerb_fgetdouble */
221 char *
222 gerb_fgetstring(gerb_file_t *fd, char term)
224 char *strend = NULL;
225 char *newstr;
226 char *i, *iend;
227 int len;
229 iend = fd->data + fd->datalen;
230 for (i = fd->data + fd->ptr; i < iend; i++) {
231 if (*i == term) {
232 strend = i;
233 break;
237 if (strend == NULL)
238 return NULL;
240 len = strend - (fd->data + fd->ptr);
242 newstr = (char *)g_malloc(len + 1);
243 if (newstr == NULL)
244 return NULL;
245 strncpy(newstr, fd->data + fd->ptr, len);
246 newstr[len] = '\0';
247 fd->ptr += len;
249 return newstr;
250 } /* gerb_fgetstring */
253 void
254 gerb_ungetc(gerb_file_t *fd)
256 if (fd->ptr)
257 fd->ptr--;
259 return;
260 } /* gerb_ungetc */
263 void
264 gerb_fclose(gerb_file_t *fd)
266 if (fd) {
267 #ifdef HAVE_SYS_MMAN_H
268 if (munmap(fd->data, fd->datalen) < 0)
269 GERB_FATAL_ERROR("munmap:%s", strerror(errno));
270 #else
271 g_free(fd->data);
272 #endif
273 if (fclose(fd->fd) == EOF)
274 GERB_FATAL_ERROR("fclose:%s", strerror(errno));
275 g_free(fd);
278 return;
279 } /* gerb_fclose */
282 char *
283 gerb_find_file(char const * filename, char **paths)
285 char *curr_path = NULL;
286 char *complete_path = NULL;
287 int i;
289 #ifdef DEBUG
290 if( DEBUG > 0 ) {
291 for (i = 0; paths[i] != NULL; i++) {
292 printf("%s(): paths[%d] = \"%s\"\n", __FUNCTION__, i, paths[i]);
295 #endif
297 for (i = 0; paths[i] != NULL; i++) {
298 dprintf("%s(): Try paths[%d] = \"%s\"\n", __FUNCTION__, i, paths[i]);
301 * Environment variables start with a $ sign
303 if (paths[i][0] == '$') {
304 char *env_name, *env_value, *tmp;
305 int len;
307 /* Extract environment name. Remember we start with a $ */
309 tmp = strchr(paths[i], G_DIR_SEPARATOR);
310 if (tmp == NULL)
311 len = strlen(paths[i]) - 1;
312 else
313 len = tmp - paths[i] - 1;
314 env_name = (char *)g_malloc(len + 1);
315 if (env_name == NULL)
316 return NULL;
317 strncpy(env_name, (char *)(paths[i] + 1), len);
318 env_name[len] = '\0';
320 env_value = getenv(env_name);
321 dprintf("%s(): Trying \"%s\" = \"%s\" from the environment\n",
322 __FUNCTION__, env_name,
323 env_value == NULL ? "(null)" : env_value);
325 if (env_value == NULL) {
326 curr_path = NULL;
327 } else {
328 curr_path = (char *)g_malloc(strlen(env_value) + strlen(&paths[i][len + 1]) + 1);
329 if (curr_path == NULL)
330 return NULL;
331 strcpy(curr_path, env_value);
332 strcat(curr_path, &paths[i][len + 1]);
333 g_free(env_name);
335 } else {
336 curr_path = paths[i];
339 if (curr_path != NULL) {
341 * Build complete path (inc. filename) and check if file exists.
343 complete_path = (char *)g_malloc(strlen(curr_path) + strlen(filename) + 2);
344 if (complete_path == NULL)
345 return NULL;
346 strcpy(complete_path, curr_path);
347 complete_path[strlen(curr_path)] = G_DIR_SEPARATOR;
348 complete_path[strlen(curr_path) + 1] = '\0';
349 strncat(complete_path, filename, strlen(filename));
351 if (paths[i][0] == '$') {
352 g_free(curr_path);
353 curr_path = NULL;
356 dprintf("%s(): Tring to access \"%s\"\n", __FUNCTION__,
357 complete_path);
359 if (access(complete_path, R_OK) != -1)
360 break;
362 g_free(complete_path);
363 complete_path = NULL;
367 if (complete_path == NULL)
368 errno = ENOENT;
370 dprintf("%s(): returning complete_path = \"%s\"\n", __FUNCTION__,
371 complete_path == NULL ? "(null)" : complete_path);
373 return complete_path;
374 } /* gerb_find_file */
380 * Extract the file names in a zip archive and return them in a GSList.
382 int
383 gerb_filenames_in_zip(char *zipname, GSList **filenames)
385 unzFile zfd;
386 int status;
387 int idx = 0;
388 gchar *zfilename;
389 GSList *fn = NULL;
391 /* Now try to open the zip file given and determine which files are in it*/
392 zfd = unzOpen(zipname);
393 if (zfd == NULL) {
394 GERB_FATAL_ERROR("unzOpen failed on %s\n", zipname);
395 return -1;
398 if (unzGoToFirstFile(zfd) != UNZ_OK) {
399 GERB_FATAL_ERROR("Failed to go to first file in %s\n", zipname);
400 unzClose(zfd);
401 return -1;
404 /* Insert all filenames in zip to a GSList */
405 zfilename = g_malloc(GERB_FILE_ZFILENAME_LEN_MAX);
406 while (1) {
407 memset(zfilename, 0, GERB_FILE_ZFILENAME_LEN_MAX);
408 unzGetCurrentFileInfo(zfd,
409 NULL,
410 zfilename,
411 255,
412 NULL,
414 NULL,
416 fn = g_slist_append(fn, (gpointer)g_strdup(zfilename));
417 idx++;
418 dprintf("%s(): Found file \"%s\" in the zip file\n",
419 __FUNCTION__, zfilename);
421 status = unzGoToNextFile(zfd);
422 if (status == UNZ_END_OF_LIST_OF_FILE) {
423 break;
425 if (status != UNZ_OK) {
426 GERB_FATAL_ERROR("Failed to go to next file.\n");
427 unzClose(zfd);
428 g_free(zfilename);
429 return -1;
432 g_free(zfilename);
434 *filenames = fn;
436 unzClose(zfd);
438 return idx;
439 } /* gerb_filenames_in_zip */