/* * Copyright (C) 2000, Matias Atria * * 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 */ #include #include #include #include #include #include #include #include #include "common.h" #include "private.h" static char *const messages[] = { _G("Ooops!"), _G("Aieeeee!!"), _G("Ouch!"), _G("Houston, we have a problem"), _G("3.. 2.. 1.. BOOM!"), _G("I'm history"), _G("I'm going down"), _G("I smell a rat") }; #define NMSGS (sizeof(messages) / sizeof(char *)) static FILE *logfile = NULL; static int _mdvi_log_level; int mdvi_set_logfile(const char *filename); int mdvi_set_logstream(FILE *file); int mdvi_set_loglevel(int level); static void vputlog(int level, const char *head, const char *format, va_list ap) { if(logfile != NULL && _mdvi_log_level >= level) { if(head != NULL) fprintf(logfile, "%s: ", head); vfprintf(logfile, format, ap); } } int mdvi_set_logfile(const char *filename) { FILE *f = NULL; if(filename && (f = fopen(filename, "w")) == NULL) return -1; if(logfile != NULL && !isatty(fileno(logfile))) { fclose(logfile); logfile = NULL; } if(filename) logfile = f; return 0; } int mdvi_set_logstream(FILE *file) { if(logfile && !isatty(fileno(logfile))) { fclose(logfile); logfile = NULL; } logfile = file; return 0; } int mdvi_set_loglevel(int level) { int old = _mdvi_log_level; _mdvi_log_level = level; return old; } #ifndef NODEBUG Uint32 _mdvi_debug_mask = 0; void __debug(int mask, const char *format, ...) { va_list ap; va_start(ap, format); if(_mdvi_debug_mask & mask) { if(!DEBUGGING(SILENT)) { fprintf(stderr, "Debug: "); vfprintf(stderr, format, ap); fflush(stderr); } #ifndef __GNUC__ /* let's be portable */ va_end(ap); va_start(ap, format); #endif vputlog(LOG_DEBUG, "Debug", format, ap); } va_end(ap); } #endif void message(const char *format, ...) { va_list ap; va_start(ap, format); if(_mdvi_log_level >= LOG_INFO) { fprintf(stderr, "%s: ", program_name); vfprintf(stderr, format, ap); #ifndef __GNUC__ va_end(ap); va_start(ap, format); #endif } vputlog(LOG_INFO, NULL, format, ap); va_end(ap); } void crash(const char *format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, "%s: %s: ", program_name, gettext(messages[(int)time(NULL) % NMSGS])); vfprintf(stderr, format, ap); #ifndef __GNUC__ /* let's be portable */ va_end(ap); va_start(ap, format); #endif vputlog(LOG_ERROR, _("Crashing"), format, ap); va_end(ap); abort(); } void error(const char *format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, _("%s: Error: "), program_name); vfprintf(stderr, format, ap); #ifndef __GNUC__ /* let's be portable */ va_end(ap); va_start(ap, format); #endif vputlog(LOG_ERROR, _("Error"), format, ap); va_end(ap); } void warning(const char *format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, _("%s: Warning: "), program_name); vfprintf(stderr, format, ap); #ifndef __GNUC__ /* let's be portable */ va_end(ap); va_start(ap, format); #endif vputlog(LOG_WARN, _("Warning"), format, ap); va_end(ap); } void fatal(const char *format, ...) { va_list ap; va_start(ap, format); fprintf(stderr, _("%s: Fatal: "), program_name); vfprintf(stderr, format, ap); #ifndef __GNUC__ /* let's be portable */ va_end(ap); va_start(ap, format); #endif vputlog(LOG_ERROR, _("Fatal"), format, ap); va_end(ap); #ifndef NODEBUG abort(); #else exit(EXIT_FAILURE); #endif } void *mdvi_malloc(size_t nelems) { void *ptr = malloc(nelems); if(ptr == NULL) fatal(_("out of memory allocating %u bytes\n"), (unsigned)nelems); return ptr; } void *mdvi_realloc(void *data, size_t newsize) { void *ptr; if(newsize == 0) crash(_("attempted to reallocate with zero size\n")); ptr = realloc(data, newsize); if(ptr == NULL) fatal(_("failed to reallocate %u bytes\n"), (unsigned)newsize); return ptr; } void *mdvi_calloc(size_t nmemb, size_t size) { void *ptr; if(nmemb == 0) crash(_("attempted to callocate 0 members\n")); if(size == 0) crash(_("attempted to callocate %u members with size 0\n"), (unsigned)nmemb); ptr = calloc(nmemb, size); if(ptr == 0) fatal(_("failed to allocate %ux%u bytes\n"), (unsigned)nmemb, (unsigned)size); return ptr; } void mdvi_free(void *ptr) { if(ptr == NULL) crash(_("attempted to free NULL pointer\n")); free(ptr); } char *mdvi_strdup(const char *string) { int length; char *ptr; length = strlen(string) + 1; ptr = (char *)mdvi_malloc(length); memcpy(ptr, string, length); return ptr; } /* `to' should have room for length+1 bytes */ char *mdvi_strncpy(char *to, const char *from, size_t length) { strncpy(to, from, length); to[length] = '\0'; return to; } char *mdvi_strndup(const char *string, size_t length) { int n; char *ptr; n = strlen(string); if(n > length) n = length; ptr = (char *)mdvi_malloc(n + 1); memcpy(ptr, string, n); return ptr; } void *mdvi_memdup(const void *data, size_t length) { void *ptr = mdvi_malloc(length); memcpy(ptr, data, length); return ptr; } double unit2pix_factor(const char *spec) { double val; double factor; const char *p, *q; static const char *units = "incmmmmtptpcddccspbpftydcs"; val = 0.0; for(p = spec; *p >= '0' && *p <= '9'; p++) val = 10.0 * val + (double)(*p - '0'); if(*p == '.') { p++; factor = 0.1; while(*p && *p >= '0' && *p <= '9') { val += (*p++ - '0') * factor; factor = factor * 0.1; } } factor = 1.0; for(q = units; *q; q += 2) { if(p[0] == q[0] && p[1] == q[1]) break; } switch((int)(q - units)) { /*in*/ case 0: factor = 1.0; break; /*cm*/ case 2: factor = 1.0 / 2.54; break; /*mm*/ case 4: factor = 1.0 / 25.4; break; /*mt*/ case 6: factor = 1.0 / 0.0254; break; /*pt*/ case 8: factor = 1.0 / 72.27; break; /*pc*/ case 10: factor = 12.0 / 72.27; break; /*dd*/ case 12: factor = (1238.0 / 1157.0) / 72.27; break; /*cc*/ case 14: factor = 12 * (1238.0 / 1157.0) / 72.27; break; /*sp*/ case 16: factor = 1.0 / (72.27 * 65536); break; /*bp*/ case 18: factor = 1.0 / 72.0; break; /*ft*/ case 20: factor = 12.0; break; /*yd*/ case 22: factor = 36.0; break; /*cs*/ case 24: factor = 1.0 / 72000.0; break; default: factor = 1.0; } return factor * val; } int unit2pix(int dpi, const char *spec) { double factor = unit2pix_factor(spec); return (int)(factor * dpi + 0.5); } Ulong get_mtime(int fd) { struct stat st; if(fstat(fd, &st) == 0) return (Ulong)st.st_mtime; return 0; } char *xstradd(char *dest, size_t *size, size_t n, const char *src, size_t m) { if(m == 0) m = strlen(src); if(n + m >= *size) { dest = mdvi_realloc(dest, n + m + 1); *size = n + m + 1; } memcpy(dest + n, src, m); dest[n + m] = 0; return dest; } char *getword(char *string, const char *delim, char **end) { char *ptr; char *word; /* skip leading delimiters */ for(ptr = string; *ptr && strchr(delim, *ptr); ptr++); if(*ptr == 0) return NULL; word = ptr++; /* skip non-delimiters */ while(*ptr && !strchr(delim, *ptr)) ptr++; *end = (char *)ptr; return word; } char *getstring(char *string, const char *delim, char **end) { char *ptr; char *word; int quoted = 0; /* skip leading delimiters */ for(ptr = string; *ptr && strchr(delim, *ptr); ptr++); if(ptr == NULL) return NULL; quoted = (*ptr == '"'); if(quoted) for(word = ++ptr; *ptr && *ptr != '"'; ptr++); else for(word = ptr; *ptr && !strchr(delim, *ptr); ptr++); *end = (char *)ptr; return word; } static long pow2(size_t n) { long x = 8; /* don't bother allocating less than this */ while(x < n) x <<= 1L; return x; } void dstring_init(Dstring *dstr) { dstr->data = NULL; dstr->size = 0; dstr->length = 0; } int dstring_append(Dstring *dstr, const char *string, int len) { if(len < 0) len = strlen(string); if(len) { if(dstr->length + len >= dstr->size) { dstr->size = pow2(dstr->length + len + 1); dstr->data = mdvi_realloc(dstr->data, dstr->size); } memcpy(dstr->data + dstr->length, string, len); dstr->length += len; dstr->data[dstr->length] = 0; } else if(dstr->size == 0) { ASSERT(dstr->data == NULL); dstr->size = 8; dstr->data = mdvi_malloc(8); dstr->data[0] = 0; } return dstr->length; } int dstring_copy(Dstring *dstr, int pos, const char *string, int len) { ASSERT(pos >= 0); if(len < 0) len = strlen(string); if(len) { if(pos + len >= dstr->length) { dstr->length = pos; return dstring_append(dstr, string, len); } memcpy(dstr->data + pos, string, len); } return dstr->length; } int dstring_insert(Dstring *dstr, int pos, const char *string, int len) { ASSERT(pos >= 0); if(pos == dstr->length) return dstring_append(dstr, string, len); if(len < 0) len = strlen(string); if(len) { if(dstr->length + len >= dstr->size) { dstr->size = pow2(dstr->length + len + 1); dstr->data = mdvi_realloc(dstr->data, dstr->size); } /* make room */ memmove(dstr->data + pos, dstr->data + pos + len, len); /* now copy */ memcpy(dstr->data + pos, string, len); dstr->length += len; dstr->data[dstr->length] = 0; } return dstr->length; } int dstring_new(Dstring *dstr, const char *string, int len) { if(len < 0) len = strlen(string); if(len) { dstr->size = pow2(len + 1); dstr->data = mdvi_malloc(dstr->size * len); memcpy(dstr->data, string, len); } else dstring_init(dstr); return dstr->length; } void dstring_reset(Dstring *dstr) { if(dstr->data) mdvi_free(dstr->data); dstring_init(dstr); }