]> www.wagner.pp.ru Git - oss/catdoc.git/blob - src/fileutil.c
Fix resource leaks found by cppcheck
[oss/catdoc.git] / src / fileutil.c
1 /*
2   Copyright 1998-2003 Victor Wagner
3   Copyright 2003 Alex Ott
4   This file is released under the GPL.  Details can be
5   found in the file COPYING accompanying this distribution.
6 */
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10 #include <unistd.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <sys/stat.h>
14 #include <stdlib.h>
15 #include "catdoc.h"
16 #if defined(MSDOS) && !defined(__MSDOS__)
17 #define __MSDOS__
18 #endif
19 #if defined(__MSDOS__) || defined(_WIN32)
20 #include <dir.h>
21 #include <dos.h>
22 #else
23 #include <glob.h>
24 #endif
25
26
27 /************************************************************************/
28 /*  Copies component of string starting with p and ending one char      */
29 /*  before q into path_buf, expanding ~ if neccessary                   */
30 /************************************************************************/
31 int prepare_path_buf(char *path_buf, const char *start, const char *end) {
32         if (*start == '~' && start[1] == DIR_SEP) {
33                 char *home=getenv("HOME");
34                 start++;
35                 if (!home) {
36                         if (end-start>PATH_BUF_SIZE) return 0;
37                         strncpy(path_buf,start,end-start);
38                         path_buf[end-start]=0;
39                 } else {
40                         int l = strlen(home);
41                         if (l+(end-start)>PATH_BUF_SIZE) return 0;
42                         strcpy(path_buf,home);
43                         strncpy(path_buf+l,start,end-start);
44                         path_buf[end-start+l]=0;
45                 }       
46         } else {        
47                         if (end-start>PATH_BUF_SIZE) return 0;
48                         strncpy(path_buf,start,end-start);
49                         path_buf[end-start]=0;
50         }
51         /* Empty list element means current directory */
52         if (!*path_buf) {
53                 path_buf[0]='.';
54                 path_buf[1]=0;
55 #ifdef __MSDOS__
56         } else {
57                 strcpy(path_buf,add_exe_path(path_buf)); /* safe, becouse
58                                                                                                         add_exe_path knows about PATH_BUF_SIZE */
59 #endif
60         }
61         return 1;
62
63 }       
64 /************************************************************************/
65 /* Searches for file name in specified list of directories. Sets        */
66 /* Returns dynamically allocated full path or NULL. if nothing          */
67 /* appropriate   Expects name to be dynamically allocated and frees it  */
68 /************************************************************************/
69 char *find_file(char *name, const char *path)
70 { const char *p;
71         char *q;
72         char path_buf[PATH_BUF_SIZE];
73         char dir_sep[2]={DIR_SEP,0};
74         for (p=path;p;p=(q?(q+1):NULL)) {
75                 q=strchr(p,LIST_SEP);
76                 if (q) {
77                         if (!prepare_path_buf(path_buf,p,q)) continue;
78                 } else {
79                         if (!prepare_path_buf(path_buf,p,p+strlen(p))) continue;
80                 }
81                 strcat(path_buf,dir_sep); /* always one char */
82                 if (strlen(path_buf)+strlen(name)>=PATH_BUF_SIZE) 
83                         continue; /* Ignore too deeply nested directories */
84                 strcat(path_buf,name);
85                 if (access(path_buf,0)==0) {
86                         free(name); 
87                         return strdup(path_buf);
88                 }
89         }
90         /* if we are here, nothing found */
91         free(name); 
92         return NULL;
93 }
94
95 /************************************************************************/
96 /* Searches for charset with given name and put pointer to malloced copy*/
97 /* of its name into first arg if found. Otherwise leaves first arg      */
98 /*  unchanged. Returns non-zero on success                              */ 
99 /************************************************************************/
100 int check_charset(char **filename,const char *charset) {
101         char *tmppath;
102         if (!strncmp(charset,"utf-8",6)) {
103                 *filename=strdup("utf-8");
104                 return 1;
105         }   
106         tmppath=find_file(stradd(charset,CHARSET_EXT),charset_path);
107         /* Some compilers evalate both arguments of && before
108            applying, so let's not use && as in the shell */
109         if (tmppath) {
110             if (*tmppath) {
111                         *filename=strdup(charset);
112                         free(tmppath);
113                         return 1;
114                 } else {
115                         free(tmppath);
116                 }
117         }
118         return 0;
119 }
120
121 /**********************************************************************/
122 /*  Returns malloced string containing concatenation of two           */
123 /*  arguments                                                         */
124 /**********************************************************************/
125 char *stradd(const char *s1,const char *s2) 
126 { char *res;
127         res=malloc(strlen(s1)+strlen(s2)+1);
128         if (!res) {
129                 fprintf (stderr,"Out of memory!");
130                 exit(1);
131         }
132         strcpy(res,s1);
133         strcat(res,s2);
134         return res;
135 }  
136
137
138 /*
139  * In DOS, argv[0] contain full path to the program, and it is a custom
140  * to keep configuration files in same directory as program itself
141  */
142 #ifdef __MSDOS__
143 char *exe_dir(void) {
144         static char pathbuf[PATH_BUF_SIZE];
145         char *q;
146         strcpy(pathbuf,_argv[0]); /* DOS ensures, that our exe path is no
147                                                                  longer than PATH_BUF_SIZE*/
148         q=strrchr(pathbuf,DIR_SEP);
149         if (q) {
150                 *q=0;
151         } else {
152                 pathbuf[0]=0;
153         }
154         return pathbuf;
155 }
156 char *add_exe_path(const char *name) {
157         static char path[PATH_BUF_SIZE];
158         char *mypath=exe_dir();
159         /* No snprintf in Turbo C 2.0 library, so just check by hand
160            and exit if something goes wrong */
161         if (strchr(name,'%')) {
162                 /* there is substitution */
163                 if (strlen(name)-1+strlen(mypath)>=PATH_BUF_SIZE) {
164                         fprintf(stderr,"Invalid config file. file name \"%s\" too long "
165                                         "after substitution\n",name);
166                         exit(1);
167                 }   
168                 sprintf(path,name,exe_dir());
169                 return path;
170         } else {
171                 return name;
172         }  
173 }
174 #endif 
175 /*********************************************************************/
176 /* Prints out list of available charsets, i.e. names without extension *
177  * of all .txt files in the charset path + internally-supported utf-8  *
178  ************************************************************************/ 
179
180 void list_charsets(void) {
181         const char *p;
182         char *q;
183         char path_buf[PATH_BUF_SIZE];
184         char dir_sep[2]={DIR_SEP,0};
185         char **ptr;
186 #ifdef __MSDOS__
187         struct ffblk ffblock;
188         int res,col;
189 #else
190         glob_t glob_buf;
191         int count,glob_flags=GLOB_ERR;
192
193         memset(&glob_buf,0,sizeof(glob_t));
194 #endif
195         for (p=charset_path;p;p=(q?(q+1):NULL)) {
196                 q=strchr(p,LIST_SEP);
197                 if (q) {
198                         if (q-p>=PATH_BUF_SIZE) {
199                                 /* Oops, dir name too long, perhabs broken config file */
200                                 continue;
201                         }
202                         strncpy(path_buf,p,q-p);
203                         path_buf[q-p]=0;
204                 } else {
205                         if (strlen(p)>=PATH_BUF_SIZE) continue;
206                         strcpy(path_buf,p);
207                 }
208                 /* Empty list element means current directory */
209                 if (!*path_buf) {
210                         path_buf[0]='.';
211                         path_buf[1]=0;
212 #ifdef __MSDOS__
213                 } else {
214                         strcpy(path_buf,add_exe_path(path_buf)); /* safe, becouse
215                                                                                                                 add_exe_path knows about PATH_BUF_SIZE */
216 #endif
217                 }
218                 strcat(path_buf,dir_sep); /* always one char */
219                 if (strlen(path_buf)+6>=PATH_BUF_SIZE)
220                         continue; /* Ignore too deeply nested directories */
221                 strcat(path_buf,"*.txt");
222 #ifdef __MSDOS__
223                 res=findfirst(path_buf,&ffblock,FA_RDONLY | FA_HIDDEN | FA_ARCH);
224                 col=1;
225                 printf("Available charsets:\n"); 
226                 while (!res) {
227                         char name[12],*src,*dest;
228                         dest=name;
229                         src=ffblock.ff_name;
230                         for (dest=name,src=ffblock.ff_name;*src && *src !='.';dest++,src++)
231                                 *dest=tolower(*src);
232                         *dest++=(col<5)?'\t':'\n';
233                         if (++col>5) col=1;
234                         *dest=0;
235                         printf("%10s",name);
236                         res=findnext(&ffblock);
237                 }
238 #else
239                 switch (glob(path_buf,glob_flags,NULL,&glob_buf)) {
240                         case 0:
241 #ifdef GLOB_NOMATCH
242                         case GLOB_NOMATCH:
243 #endif
244                                 break;
245                         default:
246                                 perror("catdoc");
247                                 exit(1);
248                 }
249                 glob_flags|=GLOB_APPEND;
250 #endif
251         }
252 #ifdef __MSDOS__
253         fputs("utf-8\n",stdout);
254 #else
255         count=0;printf("Available charsets:"); 
256         for (ptr=glob_buf.gl_pathv;*ptr;ptr++) {
257                 printf("%c",(count++)%5?'\t':'\n');
258                 p=strrchr(*ptr,dir_sep[0]);
259                 if (!p) continue;
260                 p++;
261                 if ((q=strchr(p,'.'))) *q=0;
262                 fputs(p,stdout);
263         }  
264         printf("%c",(count++)%5?'\t':'\n');
265         fputs("utf-8",stdout);
266         printf("\n");
267         globfree(&glob_buf);
268 #endif   
269 }