1 /*
2 TiMidity -- Experimental MIDI to WAVE converter
3 Copyright (C) 1995 Tuukka Toivonen <toivonen@clinet.fi>
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the Perl Artistic License, available in COPYING.
7 */
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <string.h>
12
13 #include <errno.h>
14 #include "config.h"
15 #include "common.h"
16 #include "output.h"
17 #include "ctrlmode.h"
18
19 /* I guess "rb" should be right for any libc */
20 #define OPEN_MODE "rb"
21
22 char current_filename[PATH_MAX];
23
24 static PathList *pathlist=NULL;
25
26 /* Try to open a file for reading. If the filename ends in one of the
27 defined compressor extensions, pipe the file through the decompressor */
try_to_open(const char * name,int decompress,int noise_mode)28 static FILE *try_to_open(const char *name, int decompress, int noise_mode)
29 {
30 FILE *fp;
31
32 fp=fopen(name, OPEN_MODE); /* First just check that the file exists */
33
34 if (!fp)
35 return 0;
36
37 #ifdef DECOMPRESSOR_LIST
38 if (decompress)
39 {
40 int l,el;
41 static char *decompressor_list[] = DECOMPRESSOR_LIST, **dec;
42 const char *cp;
43 char tmp[PATH_MAX], tmp2[PATH_MAX], *cp2;
44 /* Check if it's a compressed file */
45 l=strlen(name);
46 for (dec=decompressor_list; *dec; dec+=2)
47 {
48 el=strlen(*dec);
49 if ((el>=l) || (strcmp(name+l-el, *dec)))
50 continue;
51
52 /* Yes. Close the file, open a pipe instead. */
53 fclose(fp);
54
55 /* Quote some special characters in the file name */
56 cp=name;
57 cp2=tmp2;
58 while (*cp)
59 {
60 switch(*cp)
61 {
62 case '\'':
63 case '\\':
64 case ' ':
65 case '`':
66 case '!':
67 case '"':
68 case '&':
69 case ';':
70 *cp2++='\\';
71 }
72 *cp2++=*cp++;
73 }
74 *cp2=0;
75
76 sprintf(tmp, *(dec+1), tmp2);
77 fp=popen(tmp, "r");
78 break;
79 }
80 }
81 #endif
82
83 return fp;
84 }
85
86 /* This is meant to find and open files for reading, possibly piping
87 them through a decompressor. */
open_file(const char * name,int decompress,int noise_mode)88 FILE *open_file(const char *name, int decompress, int noise_mode)
89 {
90 FILE *fp;
91 PathList *plp;
92 int l;
93
94 if (!name || !(*name))
95 {
96 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Attempted to open nameless file.");
97 return 0;
98 }
99
100 if (pathlist==NULL) {
101 /* Generate path list */
102 #ifdef DEFAULT_PATH
103 add_to_pathlist(DEFAULT_PATH);
104 #endif
105 #ifdef DEFAULT_PATH1
106 add_to_pathlist(DEFAULT_PATH1);
107 #endif
108 #ifdef DEFAULT_PATH2
109 add_to_pathlist(DEFAULT_PATH2);
110 #endif
111 #ifdef DEFAULT_PATH3
112 add_to_pathlist(DEFAULT_PATH3);
113 #endif
114 }
115
116 /* First try the given name */
117
118 strncpy(current_filename, name, PATH_MAX - 1);
119 current_filename[PATH_MAX - 1]='\0';
120
121 ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Trying to open %s", current_filename);
122 if ((fp=try_to_open(current_filename, decompress, noise_mode)))
123 return fp;
124
125 #ifdef ENOENT
126 if (noise_mode && (errno != ENOENT))
127 {
128 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
129 current_filename, strerror(errno));
130 return 0;
131 }
132 #endif
133
134 plp=pathlist;
135 if (name[0] != PATH_SEP)
136 while (plp) /* Try along the path then */
137 {
138 *current_filename=0;
139 l=strlen(plp->path);
140 if(l)
141 {
142 strcpy(current_filename, plp->path);
143 if(current_filename[l-1]!=PATH_SEP)
144 strcat(current_filename, PATH_STRING);
145 }
146 strcat(current_filename, name);
147 ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Trying to open %s", current_filename);
148 if ((fp=try_to_open(current_filename, decompress, noise_mode)))
149 return fp;
150 #ifdef ENOENT
151 if (noise_mode && (errno != ENOENT))
152 {
153 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s",
154 current_filename, strerror(errno));
155 return 0;
156 }
157 #endif
158 plp=plp->next;
159 }
160
161 /* Nothing could be opened. */
162
163 *current_filename=0;
164
165 if (noise_mode>=2)
166 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", name, strerror(errno));
167
168 return 0;
169 }
170
171 /* This closes files opened with open_file */
close_file(FILE * fp)172 void close_file(FILE *fp)
173 {
174 #ifdef DECOMPRESSOR_LIST
175 if (pclose(fp)) /* Any better ideas? */
176 #endif
177 fclose(fp);
178
179 strncpy(current_filename, "MIDI file", PATH_MAX - 1);
180 }
181
182 /* This is meant for skipping a few bytes in a file or fifo. */
skip(FILE * fp,size_t len)183 void skip(FILE *fp, size_t len)
184 {
185 size_t c;
186 char tmp[PATH_MAX];
187 while (len>0)
188 {
189 c=len;
190 if (c>PATH_MAX) c=PATH_MAX;
191 len-=c;
192 if (c!=fread(tmp, 1, c, fp))
193 ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: skip: %s",
194 current_filename, strerror(errno));
195 }
196 }
197
198 /* This'll allocate memory or die. */
safe_malloc(size_t count)199 void *safe_malloc(size_t count)
200 {
201 void *p;
202 if (count > (1<<21))
203 {
204 ctl->cmsg(CMSG_FATAL, VERB_NORMAL,
205 "Strange, I feel like allocating %d bytes. This must be a bug.",
206 count);
207 }
208 else if ((p=malloc(count)))
209 return p;
210 else
211 ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Sorry. Couldn't malloc %d bytes.", count);
212
213 ctl->close();
214 exit(10);
215 return(NULL);
216 }
217
218 /* This adds a directory to the path list */
add_to_pathlist(const char * s)219 void add_to_pathlist(const char *s)
220 {
221 PathList *plp=safe_malloc(sizeof(PathList));
222 strcpy((plp->path=safe_malloc(strlen(s)+1)),s);
223 plp->next=pathlist;
224 pathlist=plp;
225 }
226
227 /* Free memory associated to path list */
free_pathlist(void)228 void free_pathlist(void)
229 {
230 PathList *plp, *next_plp;
231
232 plp = pathlist;
233 while (plp) {
234 if (plp->path) {
235 free(plp->path);
236 plp->path=NULL;
237 }
238 next_plp = plp->next;
239 free(plp);
240 plp = next_plp;
241 }
242 pathlist = NULL;
243 }
244