More reformatting.
[ahxm.git] / support.c
blobbcb511c89744822582a074765d04b1714abd13fa
1 /*
3 Ann Hell Ex Machina - Music Software
4 Copyright (C) 2003/2008 Angel Ortega <angel@triptico.com>
6 support.c - Miscellaneous support functions
8 This program is free software; you can redistribute it and/or
9 modify it under the terms of the GNU General Public License
10 as published by the Free Software Foundation; either version 2
11 of the License, or (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
22 http://www.triptico.com
26 #include "config.h"
28 #include <stdio.h>
29 #include <string.h>
30 #include <stdlib.h>
31 #include <unistd.h>
32 #include <sys/stat.h>
33 #include <sys/types.h>
35 #include "ahxm.h"
36 #include "sha1.h"
39 /** data **/
41 static char **library_path = NULL;
42 static int n_library_paths = 0;
44 static char located_file[2048];
46 /* global verbose flag */
47 int verbose = 1;
49 /* global tracing flag */
50 int trace = 0;
52 /* transparent converters */
53 struct transconv {
54 const char *from; /* extension from */
55 const char *to; /* extension to */
56 const char *convcmd; /* sprintf() format for converting command */
59 static struct transconv *transconvs = NULL;
60 static int n_transconvs = 0;
63 /** code **/
65 /**
66 * libpath_add - Adds a directory path to the search path
67 * @path: the directory path
68 * @strip: flag to strip the upper level
70 * Adds @path to the list of searchable paths for libpath_fopen(),
71 * optionally stripping the upper level if @strip is set.
72 * The last part of the path is stripped before being stored,
73 * and duplication is avoided.
75 void libpath_add(const char *path, int strip)
77 int n;
78 char *ptr;
79 char *p;
81 /* if path starts with ~, set it to $HOME */
82 if (*path == '~') {
83 char *new;
84 char *home;
86 if ((home = getenv("HOME")) == NULL)
87 return;
89 if ((new = malloc(strlen(home) + strlen(path) + 2)) == NULL)
90 return;
92 strcpy(new, home);
93 strcat(new, "/");
94 strcat(new, path + 1);
96 p = new;
98 else {
99 /* just duplicate */
100 p = strdup(path);
103 /* if no directory path remains, abort */
104 if ((ptr = strrchr(p, '/')) == NULL) {
105 free(p);
106 return;
109 /* strip the filename part */
110 if (strip)
111 *ptr = '\0';
113 /* now try to find if that path is already stored */
114 for (n = 0; n < n_library_paths; n++) {
115 if (strcmp(p, library_path[n]) == 0) {
116 /* found; free and return */
117 free(p);
118 return;
122 /* add room for the new path */
123 n_library_paths++;
124 library_path =
125 (char **) realloc(library_path, n_library_paths * sizeof(char *));
127 /* store */
128 library_path[n_library_paths - 1] = p;
133 * libpath_fopen - Opens a file, optionally searching in a path list
134 * @filename: the file name
135 * @mode: the file mode
137 * Opens a file. If the file is found as is, it's opened;
138 * otherwise, the full list of directory paths maintained by
139 * libpath_add() is searched until it's found or the
140 * end of the list is reached. Whenever a file
141 * is successfully opened, its path is also stored.
143 FILE *libpath_fopen(const char *filename, const char *mode)
145 int n;
146 FILE *f = NULL;
148 /* try first here */
149 if ((f = fopen(filename, mode)) != NULL) {
150 strncpy(located_file, filename, sizeof(located_file));
151 located_file[sizeof(located_file) - 1] = '\0';
153 libpath_add(filename, 1);
154 return f;
157 /* couldn't open; try concatenating all stored paths */
158 for (n = n_library_paths - 1; n >= 0; n--) {
159 snprintf(located_file, sizeof(located_file), "%s/%s",
160 library_path[n], filename);
161 located_file[sizeof(located_file) - 1] = '\0';
163 if ((f = fopen(located_file, mode)) != NULL) {
164 libpath_add(located_file, 1);
165 break;
169 return f;
174 * libpath_locate - Locates a file inside the path
175 * @filename: the file to be located
177 * Locates a file inside the library path maintained by libpath_fopen()
178 * and add_library_path(). If the file is found, a pointer to a static
179 * buffer containing the real path of the file is returned, or
180 * NULL otherwise.
182 char *libpath_locate(const char *filename)
184 FILE *f;
186 if ((f = libpath_fopen(filename, "r")) == NULL)
187 return NULL;
189 fclose(f);
190 return located_file;
195 * libpath_print - Prints the library path
197 * Prints the library path.
199 void libpath_print(void)
201 int n;
203 for (n = 0; n < n_library_paths; n++) {
204 if (n)
205 printf(";");
207 printf("%s", library_path[n]);
211 /** transparent conversions **/
213 void transconv_add(const char *from, const char *to, const char *convcmd)
214 /* adds a converter */
216 struct transconv *t;
218 GROW(transconvs, n_transconvs, struct transconv);
220 t = &transconvs[n_transconvs++];
222 t->from = strdup(from);
223 t->to = strdup(to);
224 t->convcmd = strdup(convcmd);
228 static char *transconv_sha_file(const char *file, const char *ext)
229 /* builds a unique cache file basename using a SHA1 hash */
231 static char c_file[64];
232 unsigned char sha1[20];
233 SHA_CTX c;
234 int n;
236 SHA1_Init(&c);
237 SHA1_Update(&c, (char *) file, strlen(file));
238 SHA1_Update(&c, (char *) ext, strlen(ext));
239 SHA1_Final(sha1, &c);
241 for (n = 0; n < sizeof(sha1); n++) {
242 char tmp[3];
244 snprintf(tmp, sizeof(tmp), "%02x", sha1[n]);
245 c_file[n * 2] = tmp[0];
246 c_file[(n * 2) + 1] = tmp[1];
249 c_file[n * 2] = '\0';
250 return c_file;
254 static char *transconv_unique_file(const char *file, const char *ext,
255 const char *dir)
256 /* builds a unique cache file name with complete path */
258 static char tmp[2048];
259 char *c_path = NULL;
261 if ((c_path = getenv("TEMP")) == NULL)
262 if ((c_path = getenv("TMP")) == NULL)
263 c_path = "/tmp";
265 /* build the directory cache name */
266 snprintf(tmp, sizeof(tmp), "%s/%s-%d", c_path, dir, getuid());
267 tmp[sizeof(tmp) - 1] = '\0';
269 /* create the cache directory */
270 #if CONFOPT_MKDIR_ARGS == 2
271 mkdir(tmp, 0755);
272 #else
273 mkdir(tmp);
274 #endif
276 strcat(tmp, "/");
277 strcat(tmp, transconv_sha_file(file, ext));
278 strcat(tmp, ext);
280 return tmp;
284 char *transconv_pipe(const char *cmd, const char *ext, const char *dir)
285 /* executes cmd as a pipe */
287 char *c_file = transconv_unique_file(cmd, ext, dir);
289 /* does the file already exist? */
290 if (access(c_file, R_OK)) {
291 char tmp[2048];
293 snprintf(tmp, sizeof(tmp), cmd, c_file);
294 tmp[sizeof(tmp) - 1] = '\0';
296 if (verbose >= 2)
297 printf("Converting: %s\n", tmp);
299 system(tmp);
302 return c_file;
306 char *transconv(const char *file, const char *ext, const char *dir)
307 /* converts using the transparent converters and the cache, if needed */
309 char *this_ext;
310 char *c_file;
311 int n;
312 struct transconv *t;
314 /* gets this file extension */
315 if (file == NULL || (this_ext = strrchr(file, '.')) == NULL)
316 return NULL;
318 /* if it's already the desired type, do nothing */
319 if (strcmp(ext, this_ext) == 0)
320 return (char *) file;
322 /* get a unique name */
323 c_file = transconv_unique_file(file, ext, dir);
325 /* does the file already exist? */
326 if (access(c_file, R_OK) == 0)
327 return c_file;
329 /* no; look for a suitable converter */
330 for (n = 0, t = transconvs; n < n_transconvs; n++, t++) {
331 if (strcmp(t->from, ".*") == 0 ||
332 (strcmp(ext, t->to) == 0 && strcmp(this_ext, t->from) == 0)) {
333 char tmp[2048];
335 /* found a converter! just do it */
336 snprintf(tmp, sizeof(tmp), t->convcmd, c_file, file);
337 tmp[sizeof(tmp) - 1] = '\0';
339 if (verbose >= 2)
340 printf("Executing: %s\n", tmp);
342 if (system(tmp) == 0)
343 break;
344 else
345 unlink(c_file);
349 return c_file;