📄 common.c
字号:
/* TiMidity++ -- MIDI to WAVE converter and player Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp> Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA common.c */#ifdef HAVE_CONFIG_H#include "config.h"#endif /* HAVE_CONFIG_H */#include <stdio.h>#include <stdlib.h>#include <stdarg.h>#include <time.h>#ifdef HAVE_SYS_TIME_H#include <sys/time.h>#endif /* HAVE_SYS_TIME_H */#ifdef HAVE_SYS_TYPES_H#include <sys/types.h>#endif /* HAVE_SYS_TYPES_H */#ifdef HAVE_SYS_STAT_H#include <sys/stat.h>#endif /* HAVE_SYS_STAT_H */#include <fcntl.h>#ifndef NO_STRING_H#include <string.h>#else#include <strings.h>#endif#include <ctype.h>#ifndef __W32__#ifdef HAVE_UNISTD_H#include <unistd.h>#endif /* HAVE_UNISTD_H */#else#include <process.h>#include <io.h>#endif /* __W32__ */#include "timidity.h"#include "common.h"#include "output.h"#include "controls.h"#include "arc.h"#include "nkflib.h"#include "wrd.h"#include "strtab.h"#include "support.h"/* RAND_MAX must defined in stdlib.h * Why RAND_MAX is not defined at SunOS? */#if defined(sun) && !defined(SOLARIS) && !defined(RAND_MAX)#define RAND_MAX ((1<<15)-1)#endif#ifndef O_BINARY#define O_BINARY 0#endif/* #define MIME_CONVERSION */char *program_name, current_filename[1024];MBlockList tmpbuffer;char *output_text_code = NULL;int open_file_noise_mode = OF_NORMAL;#ifdef DEFAULT_PATH /* The paths in this list will be tried whenever we're reading a file */ static PathList defaultpathlist={DEFAULT_PATH,0}; static PathList *pathlist=&defaultpathlist; /* This is a linked list */#else static PathList *pathlist=0;#endifconst char *note_name[] ={ "C", "C#", "D", "D#", "E", "F", "F#", "G", "G#", "A", "A#", "B"};#ifndef TMP_MAX#define TMP_MAX 238328#endifinttmdy_mkstemp(char *tmpl){ char *XXXXXX; static uint32 value; uint32 random_time_bits; int count, fd = -1; int save_errno = errno; /* These are the characters used in temporary filenames. */ static const char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; /* This is where the Xs start. */ XXXXXX = strstr(tmpl, "XXXXXX"); if (XXXXXX == NULL) { errno = EINVAL; return -1; } /* Get some more or less random data. */#if HAVE_GETTIMEOFDAY { struct timeval tv; gettimeofday(&tv, NULL); random_time_bits = (uint32)((tv.tv_usec << 16) ^ tv.tv_sec); }#else random_time_bits = (uint32)time(NULL);#endif value += random_time_bits ^ getpid(); for (count = 0; count < TMP_MAX; value += 7777, ++count) { uint32 v = value; /* Fill in the random bits. */ XXXXXX[0] = letters[v % 62]; v /= 62; XXXXXX[1] = letters[v % 62]; v /= 62; XXXXXX[2] = letters[v % 62]; v = (v << 16) ^ value; XXXXXX[3] = letters[v % 62]; v /= 62; XXXXXX[4] = letters[v % 62]; v /= 62; XXXXXX[5] = letters[v % 62];#if defined(_MSC_VER)#define S_IRUSR 0#define S_IWUSR 0#endif fd = open(tmpl, O_RDWR | O_CREAT | O_EXCL | O_BINARY, S_IRUSR | S_IWUSR); if (fd >= 0) { errno = save_errno; return fd; } if (errno != EEXIST) return -1; } /* We got out of the loop because we ran out of combinations to try. */ errno = EEXIST; return -1;}static char *url_dumpfile(URL url, const char *ext){ char filename[1024]; char *tmpdir; int fd; FILE *fp; int n; char buff[BUFSIZ];#ifdef TMPDIR tmpdir = TMPDIR;#else tmpdir = getenv("TMPDIR");#endif if(tmpdir == NULL || strlen(tmpdir) == 0) tmpdir = PATH_STRING "tmp" PATH_STRING; if(IS_PATH_SEP(tmpdir[strlen(tmpdir) - 1])) snprintf(filename, sizeof(filename), "%sXXXXXX.%s", tmpdir, ext); else snprintf(filename, sizeof(filename), "%s" PATH_STRING "XXXXXX.%s", tmpdir, ext); fd = tmdy_mkstemp(filename); if (fd == -1) return NULL; if ((fp = fdopen(fd, "w")) == NULL) { close(fd); unlink(filename); return NULL; } while((n = url_read(url, buff, sizeof(buff))) > 0) fwrite(buff, 1, n, fp); fclose(fp); return safe_strdup(filename);}/* Try to open a file for reading. If the filename ends in one of the defined compressor extensions, pipe the file through the decompressor */struct timidity_file *try_to_open(char *name, int decompress){ struct timidity_file *tf; URL url; int len; if((url = url_arc_open(name)) == NULL) if((url = url_open(name)) == NULL) return NULL; tf = (struct timidity_file *)safe_malloc(sizeof(struct timidity_file)); tf->url = url; tf->tmpname = NULL; len = strlen(name); if(decompress && len >= 3 && strcasecmp(name + len - 3, ".gz") == 0) { int method; if(!IS_URL_SEEK_SAFE(tf->url)) { if((tf->url = url_cache_open(tf->url, 1)) == NULL) { close_file(tf); return NULL; } } method = skip_gzip_header(tf->url); if(method == ARCHIVEC_DEFLATED) { url_cache_disable(tf->url); if((tf->url = url_inflate_open(tf->url, -1, 1)) == NULL) { close_file(tf); return NULL; } /* success */ return tf; } /* fail */ url_rewind(tf->url); url_cache_disable(tf->url); }#ifdef __W32__ /* Sorry, DECOMPRESSOR_LIST and PATCH_CONVERTERS are not worked yet. */ return tf;#endif /* __W32__ */#if defined(DECOMPRESSOR_LIST) if(decompress) { static char *decompressor_list[] = DECOMPRESSOR_LIST, **dec; char tmp[1024]; /* Check if it's a compressed file */ for(dec = decompressor_list; *dec; dec += 2) { if(!check_file_extension(name, *dec, 0)) continue; tf->tmpname = url_dumpfile(tf->url, *dec); if (tf->tmpname == NULL) { close_file(tf); return NULL; } url_close(tf->url); snprintf(tmp, sizeof(tmp), *(dec+1), tf->tmpname); if((tf->url = url_pipe_open(tmp)) == NULL) { close_file(tf); return NULL; } break; } }#endif /* DECOMPRESSOR_LIST */#if defined(PATCH_CONVERTERS) if(decompress == 2) { static char *decompressor_list[] = PATCH_CONVERTERS, **dec; char tmp[1024]; /* Check if it's a compressed file */ for(dec = decompressor_list; *dec; dec += 2) { if(!check_file_extension(name, *dec, 0)) continue; tf->tmpname = url_dumpfile(tf->url, *dec); if (tf->tmpname == NULL) { close_file(tf); return NULL; } url_close(tf->url); sprintf(tmp, *(dec+1), tf->tmpname); if((tf->url = url_pipe_open(tmp)) == NULL) { close_file(tf); return NULL; } break; } }#endif /* PATCH_CONVERTERS */ return tf;}int is_url_prefix(const char *name){ int i; static char *url_proto_names[] = { "file:",#ifdef SUPPORT_SOCKET "http://", "ftp://", "news://",#endif /* SUPPORT_SOCKET */ "mime:", NULL }; for(i = 0; url_proto_names[i]; i++) if(strncmp(name, url_proto_names[i], strlen(url_proto_names[i])) == 0) return 1; return 0;}static int is_abs_path(const char *name){#ifndef __MACOS__ if (IS_PATH_SEP(name[0])) return 1;#else if (!IS_PATH_SEP(name[0]) && strchr(name, PATH_SEP) != NULL) return 1;#endif /* __MACOS__ */#ifdef __W32__ /* [A-Za-z]: (for Windows) */ if (isalpha(name[0]) && name[1] == ':') return 1;#endif /* __W32__ */ if (is_url_prefix(name)) return 1; /* assuming relative notation is excluded */ return 0;}struct timidity_file *open_with_mem(char *mem, int32 memlen, int noise_mode){ URL url; struct timidity_file *tf; errno = 0; if((url = url_mem_open(mem, memlen, 0)) == NULL) { if(noise_mode >= 2) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Can't open."); return NULL; } tf = (struct timidity_file *)safe_malloc(sizeof(struct timidity_file)); tf->url = url; tf->tmpname = NULL; return tf;}/* This is meant to find and open files for reading, possibly piping them through a decompressor. */struct timidity_file *open_file(char *name, int decompress, int noise_mode){ struct stat st; struct timidity_file *tf; PathList *plp=pathlist; int l; open_file_noise_mode = noise_mode; if (!name || !(*name)) { if(noise_mode) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "Attempted to open nameless file."); return 0; } /* First try the given name */ strncpy(current_filename, url_unexpand_home_dir(name), 1023); current_filename[1023]='\0'; if(noise_mode) ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Trying to open %s", current_filename); stat(current_filename, &st); if(!S_ISDIR(st.st_mode)) if ((tf=try_to_open(current_filename, decompress))) return tf;#ifdef __MACOS__ if(errno)#else if(errno && errno != ENOENT)#endif { if(noise_mode) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", current_filename, strerror(errno)); return 0; } if (!is_abs_path(name)) while (plp) /* Try along the path then */ { *current_filename=0; l=strlen(plp->path); if(l) { strncpy(current_filename, plp->path, sizeof(current_filename)); if(!IS_PATH_SEP(current_filename[l-1]) && current_filename[l-1] != '#' && name[0] != '#') strncat(current_filename, PATH_STRING, sizeof(current_filename) - strlen(current_filename) - 1); } strncat(current_filename, name, sizeof(current_filename) - strlen(current_filename) - 1); if(noise_mode) ctl->cmsg(CMSG_INFO, VERB_DEBUG, "Trying to open %s", current_filename); stat(current_filename, &st); if(!S_ISDIR(st.st_mode)) if ((tf=try_to_open(current_filename, decompress))) return tf;#ifdef __MACOS__ if(errno)#else if(errno && errno != ENOENT)#endif { if(noise_mode) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", current_filename, strerror(errno)); return 0; } plp=plp->next; } /* Nothing could be opened. */ *current_filename=0; if (noise_mode>=2) ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: %s", name, errno ? strerror(errno) : "Can't open file"); return 0;}/* This closes files opened with open_file */void close_file(struct timidity_file *tf){ int save_errno = errno; if(tf->url != NULL) {#ifndef __W32__ if(tf->tmpname != NULL) { int i; /* dispose the pipe garbage */ for(i = 0; tf_getc(tf) != EOF && i < 0xFFFF; i++) ; }#endif /* __W32__ */ url_close(tf->url); } if(tf->tmpname != NULL) { unlink(tf->tmpname); /* remove temporary file */ free(tf->tmpname); } free(tf); errno = save_errno;}/* This is meant for skipping a few bytes. */void skip(struct timidity_file *tf, size_t len){ url_skip(tf->url, (long)len);}char *tf_gets(char *buff, int n, struct timidity_file *tf){ return url_gets(tf->url, buff, n);}long tf_read(void *buff, int32 size, int32 nitems, struct timidity_file *tf){ return url_nread(tf->url, buff, size * nitems) / size;}long tf_seek(struct timidity_file *tf, long offset, int whence){ long prevpos; prevpos = url_seek(tf->url, offset, whence); if(prevpos == -1) ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Warning: Can't seek file position"); return prevpos;}long tf_tell(struct timidity_file *tf){ long pos; pos = url_tell(tf->url); if(pos == -1) { ctl->cmsg(CMSG_WARNING, VERB_NORMAL, "Warning: Can't get current file position"); return (long)tf->url->nread; } return pos;}void safe_exit(int status){ if(play_mode->fd != -1) { play_mode->acntl(PM_REQ_DISCARD, NULL); play_mode->close_output(); } ctl->close(); wrdt->close(); exit(status); /*NOTREACHED*/}/* This'll allocate memory or die. */void *safe_malloc(size_t count){ void *p; static int errflag = 0; if(errflag) safe_exit(10); if(count > MAX_SAFE_MALLOC_SIZE) { errflag = 1; ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Strange, I feel like allocating %d bytes. " "This must be a bug.", count); } else { if(count == 0) /* Some malloc routine return NULL if count is zero, such as * malloc routine from libmalloc.a of Solaris. * But TiMidity doesn't want to return NULL even if count is zero. */ count = 1; if((p = (void *)malloc(count)) != NULL) return p; errflag = 1; ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Sorry. Couldn't malloc %d bytes.", count); }#ifdef ABORT_AT_FATAL abort();#endif /* ABORT_AT_FATAL */ safe_exit(10); /*NOTREACHED*/}void *safe_large_malloc(size_t count){ void *p; static int errflag = 0; if(errflag) safe_exit(10); if(count == 0) /* Some malloc routine return NULL if count is zero, such as * malloc routine from libmalloc.a of Solaris. * But TiMidity doesn't want to return NULL even if count is zero. */ count = 1; if((p = (void *)malloc(count)) != NULL) return p; errflag = 1; ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Sorry. Couldn't malloc %d bytes.", count);#ifdef ABORT_AT_FATAL abort();#endif /* ABORT_AT_FATAL */ safe_exit(10); /*NOTREACHED*/}void *safe_realloc(void *ptr, size_t count){ void *p; static int errflag = 0; if(errflag) safe_exit(10); if(count > MAX_SAFE_MALLOC_SIZE) { errflag = 1; ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Strange, I feel like allocating %d bytes. " "This must be a bug.", count); } else { if (ptr == NULL) return safe_malloc(count); if(count == 0) /* Some malloc routine return NULL if count is zero, such as * malloc routine from libmalloc.a of Solaris. * But TiMidity doesn't want to return NULL even if count is zero. */ count = 1; if((p = (void *)realloc(ptr, count)) != NULL) return p; errflag = 1; ctl->cmsg(CMSG_FATAL, VERB_NORMAL, "Sorry. Couldn't malloc %d bytes.", count); }#ifdef ABORT_AT_FATAL abort();#endif /* ABORT_AT_FATAL */ safe_exit(10); /*NOTREACHED*/}/* This'll allocate memory or die. */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -